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};
15 use wgpu::util::DeviceExt;
17 #[derive(Serialize, Deserialize, PartialEq, Eq, Copy, Clone, Debug)]
18 #[serde(rename_all = "snake_case")]
25 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
26 pub struct MapRenderSettings {
27 pub leaves: LeavesMode,
28 pub opaque_liquids: bool,
31 impl Default for MapRenderSettings {
32 fn default() -> Self {
34 leaves: LeavesMode::Fancy,
35 opaque_liquids: false,
41 cube_tex_coords: [[[f32; 2]; 6]; 6],
45 // i optimized the shit out of these
46 textures: Vec<AtlasSlice>,
47 nodes: [Option<Box<NodeDef>>; u16::MAX as usize + 1],
50 type MeshQueue = HashMap<Point3<i16>, MeshData>;
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>>,
64 #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
72 const ATTRIBS: [wgpu::VertexAttribute; 3] =
73 wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2, 2 => Float32];
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,
85 vertex_buffer: wgpu::Buffer,
90 fn new(state: &State, vertices: &[Vertex]) -> Option<Self> {
91 if vertices.is_empty() {
98 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
99 label: Some("mapblock.vertex_buffer"),
100 contents: bytemuck::cast_slice(vertices),
101 usage: wgpu::BufferUsages::VERTEX,
103 num_vertices: vertices.len() as u32,
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);
115 mesh: Option<BlockMesh>,
116 mesh_blend: Option<BlockMesh>,
117 transform: MatrixUniform,
120 fn block_float_pos(pos: Vector3<i16>) -> Vector3<f32> {
121 pos.cast::<f32>().unwrap() * 16.0
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, &[]);
130 struct BlendEntry<'a> {
134 transform: &'a MatrixUniform,
137 let mut blend = Vec::new();
139 for (index, (pos, model)) in self.blocks.iter().enumerate() {
140 if let Some(mesh) = &model.mesh {
141 mesh.render(pass, &model.transform);
144 if let Some(mesh) = &model.mesh_blend {
145 blend.push(BlendEntry {
147 dist: (block_float_pos(Vector3::from(*pos))
148 - Vector3::from(state.camera.position))
151 transform: &model.transform,
156 blend.sort_unstable_by(|a, b| {
158 .partial_cmp(&b.dist)
159 .unwrap_or(std::cmp::Ordering::Equal)
160 .then_with(|| a.index.cmp(&b.index))
164 entry.mesh.render(pass, entry.transform);
168 pub fn update(&mut self, state: &mut State) {
170 self.queue_produce.lock().unwrap().deref_mut(),
171 &mut self.queue_consume,
173 for (pos, data) in self.queue_consume.drain() {
177 mesh: BlockMesh::new(state, &data.vertices),
178 mesh_blend: BlockMesh::new(state, &data.vertices_blend),
179 transform: MatrixUniform::new(
182 Matrix4::from_translation(
183 block_float_pos(pos.to_vec()) + Vector3::new(8.5, 8.5, 8.5),
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(),
202 self.queue_produce.lock().unwrap().insert(pos, data);
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);
208 let atlas_size = wgpu::Extent3d {
209 width: atlas_img.width(),
210 height: atlas_img.height(),
211 depth_or_array_layers: 1,
214 let atlas_texture = state.device.create_texture(&wgpu::TextureDescriptor {
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"),
225 state.queue.write_texture(
226 wgpu::ImageCopyTexture {
227 texture: &atlas_texture,
229 origin: wgpu::Origin3d::ZERO,
230 aspect: wgpu::TextureAspect::All,
233 wgpu::ImageDataLayout {
235 bytes_per_row: std::num::NonZeroU32::new(4 * atlas_img.width()),
236 rows_per_image: std::num::NonZeroU32::new(atlas_img.height()),
241 let atlas_view = atlas_texture.create_view(&wgpu::TextureViewDescriptor::default());
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,
255 let atlas_bind_group_layout =
258 .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
260 wgpu::BindGroupLayoutEntry {
262 visibility: wgpu::ShaderStages::FRAGMENT,
263 ty: wgpu::BindingType::Texture {
265 view_dimension: wgpu::TextureViewDimension::D2,
266 sample_type: wgpu::TextureSampleType::Float { filterable: true },
270 wgpu::BindGroupLayoutEntry {
272 visibility: wgpu::ShaderStages::FRAGMENT,
273 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
277 label: Some("atlas.bind_group_layout"),
280 let atlas_bind_group = state.device.create_bind_group(&wgpu::BindGroupDescriptor {
281 layout: &atlas_bind_group_layout,
283 wgpu::BindGroupEntry {
285 resource: wgpu::BindingResource::TextureView(&atlas_view),
287 wgpu::BindGroupEntry {
289 resource: wgpu::BindingResource::Sampler(&atlas_sampler),
292 label: Some("atlas.bind_group"),
295 let model_bind_group_layout = MatrixUniform::layout(&state.device, "mapblock");
299 .create_shader_module(wgpu::include_wgsl!("../../assets/shaders/map.wgsl"));
301 let pipeline_layout =
304 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
306 bind_group_layouts: &[
307 &atlas_bind_group_layout,
308 &model_bind_group_layout,
309 &state.camera_bind_group_layout,
311 push_constant_ranges: &[],
316 .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
318 layout: Some(&pipeline_layout),
319 vertex: wgpu::VertexState {
321 entry_point: "vs_main",
322 buffers: &[Vertex::desc()],
324 fragment: Some(wgpu::FragmentState {
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,
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,
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(),
349 multisample: wgpu::MultisampleState {
352 alpha_to_coverage_enabled: false,
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,
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())),
374 const CUBE: [[([f32; 3], [f32; 2]); 6]; 6] = [
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]),
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]),
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]),
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]),
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]),
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]),