From 8c3995298b63bfe6be7f479b3fb058709ee119be Mon Sep 17 00:00:00 2001 From: Capucho Date: Sat, 26 Sep 2020 16:43:59 +0100 Subject: [PATCH] More fixes --- Cargo.lock | 1 + voxygen/anim/Cargo.toml | 1 + voxygen/anim/src/lib.rs | 7 +- voxygen/src/mesh/greedy.rs | 26 +- voxygen/src/mesh/mod.rs | 23 +- voxygen/src/mesh/segment.rs | 609 +++++++++----------- voxygen/src/mesh/terrain.rs | 432 +++++++------- voxygen/src/render/buffer.rs | 17 +- voxygen/src/render/consts.rs | 13 +- voxygen/src/render/instances.rs | 15 +- voxygen/src/render/model.rs | 12 +- voxygen/src/render/pipelines/figure.rs | 6 +- voxygen/src/render/pipelines/fluid.rs | 4 +- voxygen/src/render/pipelines/lod_terrain.rs | 35 +- voxygen/src/render/pipelines/mod.rs | 12 +- voxygen/src/render/pipelines/particle.rs | 6 +- voxygen/src/render/pipelines/postprocess.rs | 4 +- voxygen/src/render/pipelines/shadow.rs | 19 +- voxygen/src/render/pipelines/skybox.rs | 4 +- voxygen/src/render/pipelines/sprite.rs | 8 +- voxygen/src/render/pipelines/terrain.rs | 8 +- voxygen/src/render/pipelines/ui.rs | 6 +- voxygen/src/render/renderer.rs | 466 +++++++-------- voxygen/src/render/texture.rs | 63 +- voxygen/src/run.rs | 20 +- voxygen/src/scene/figure/cache.rs | 53 +- voxygen/src/scene/figure/mod.rs | 24 +- voxygen/src/scene/lod.rs | 2 +- voxygen/src/scene/mod.rs | 106 ++-- voxygen/src/scene/particle.rs | 8 +- voxygen/src/scene/simple.rs | 17 +- voxygen/src/scene/terrain.rs | 108 ++-- voxygen/src/window.rs | 55 +- 33 files changed, 1037 insertions(+), 1153 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63d2e30ea0..c093e968fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6052,6 +6052,7 @@ dependencies = [ name = "veloren-voxygen-anim" version = "0.9.0" dependencies = [ + "bytemuck", "find_folder", "lazy_static", "libloading 0.7.0", diff --git a/voxygen/anim/Cargo.toml b/voxygen/anim/Cargo.toml index d56153f062..68f9ee5290 100644 --- a/voxygen/anim/Cargo.toml +++ b/voxygen/anim/Cargo.toml @@ -20,3 +20,4 @@ libloading = {version = "0.7", optional = true} notify = {version = "5.0.0-pre.2", optional = true} tracing = {version = "0.1", optional = true} vek = {version = "=0.14.1", features = ["serde"]} +bytemuck = { version="1.4", features=["derive"] } diff --git a/voxygen/anim/src/lib.rs b/voxygen/anim/src/lib.rs index d401074bda..b11e1410ad 100644 --- a/voxygen/anim/src/lib.rs +++ b/voxygen/anim/src/lib.rs @@ -74,16 +74,19 @@ pub use dyn_lib::init; use std::ffi::CStr; use self::vek::*; +use bytemuck::{Pod, Zeroable}; type MatRaw = [[f32; 4]; 4]; -pub type FigureBoneData = (MatRaw, MatRaw); +#[repr(C)] +#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)] +pub struct FigureBoneData(pub MatRaw, pub MatRaw); pub const MAX_BONE_COUNT: usize = 16; fn make_bone(mat: Mat4) -> FigureBoneData { let normal = mat.map_cols(Vec4::normalized); - (mat.into_col_arrays(), normal.into_col_arrays()) + FigureBoneData(mat.into_col_arrays(), normal.into_col_arrays()) } pub type Bone = Transform; diff --git a/voxygen/src/mesh/greedy.rs b/voxygen/src/mesh/greedy.rs index f39094fb7a..63defad0b0 100644 --- a/voxygen/src/mesh/greedy.rs +++ b/voxygen/src/mesh/greedy.rs @@ -1,9 +1,7 @@ -use crate::render::{self, mesh::Quad, ColLightFmt, ColLightInfo, TerrainPipeline}; +use crate::render::{mesh::Quad, ColLightInfo, TerrainVertex, Vertex}; use common_base::span; use vek::*; -type TerrainVertex = ::Vertex; - type TodoRect = ( Vec3, Vec2>, @@ -84,7 +82,7 @@ pub type SuspendedMesh<'a> = dyn for<'r> FnOnce(&'r mut ColLightInfo) + 'a; /// For an explanation of why we want this, see `SuspendedMesh`. pub struct GreedyMesh<'a> { atlas: guillotiere::SimpleAtlasAllocator, - col_lights_size: Vec2, + col_lights_size: Vec2, max_size: guillotiere::Size, suspended: Vec>>, } @@ -123,7 +121,7 @@ impl<'a> GreedyMesh<'a> { small_size_threshold, large_size_threshold, }); - let col_lights_size = Vec2::new(1u16, 1u16); + let col_lights_size = Vec2::new(1, 1); Self { atlas, col_lights_size, @@ -178,7 +176,7 @@ impl<'a> GreedyMesh<'a> { let cur_size = self.col_lights_size; let col_lights = vec![ TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254)); - usize::from(cur_size.x) * usize::from(cur_size.y) + cur_size.x as usize * cur_size.y as usize ]; let mut col_lights_info = (col_lights, cur_size); self.suspended.into_iter().for_each(|cont| { @@ -192,7 +190,7 @@ impl<'a> GreedyMesh<'a> { fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FO, FS, FP, FT>( atlas: &mut guillotiere::SimpleAtlasAllocator, - col_lights_size: &mut Vec2, + col_lights_size: &mut Vec2, max_size: guillotiere::Size, GreedyConfig { mut data, @@ -430,7 +428,7 @@ fn add_to_atlas( norm: Vec3, faces_forward: bool, max_size: guillotiere::Size, - cur_size: &mut Vec2, + cur_size: &mut Vec2, ) -> guillotiere::Rectangle { // TODO: Check this conversion. let atlas_rect; @@ -475,8 +473,8 @@ fn add_to_atlas( // a u16 and we never grew the atlas, meaning all valid coordinates within the // atlas also fit into a u16. *cur_size = Vec2::new( - cur_size.x.max(atlas_rect.max.x as u16), - cur_size.y.max(atlas_rect.max.y as u16), + cur_size.x.max(atlas_rect.max.x as u32), + cur_size.y.max(atlas_rect.max.y as u32), ); // NOTE: pos can be converted safely from usize to i32 because all legal block @@ -507,7 +505,7 @@ fn draw_col_lights( mut get_light: impl FnMut(&mut D, Vec3) -> f32, mut get_glow: impl FnMut(&mut D, Vec3) -> f32, mut get_opacity: impl FnMut(&mut D, Vec3) -> bool, - mut make_face_texel: impl FnMut(&mut D, Vec3, u8, u8) -> <::Surface as gfx::format::SurfaceTyped>::DataType, + mut make_face_texel: impl FnMut(&mut D, Vec3, u8, u8) -> [u8; 4], ) { todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| { // NOTE: Conversions are safe because width, height, and offset must be @@ -520,7 +518,7 @@ fn draw_col_lights( let uv = uv.map(|e| e.map(i32::from)); let pos = pos + draw_delta; (0..height).for_each(|v| { - let start = usize::from(cur_size.x) * usize::from(top + v) + usize::from(left); + let start = cur_size.x as usize * usize::from(top + v) + usize::from(left); (0..width) .zip(&mut col_lights[start..start + usize::from(width)]) .for_each(|(u, col_light)| { @@ -622,14 +620,14 @@ fn create_quad_greedy( push_quad(atlas_pos, dim, origin, draw_dim, norm, meta); } -pub fn create_quad( +pub fn create_quad( atlas_pos: Vec2, dim: Vec2>, origin: Vec3, draw_dim: Vec2>, norm: Vec3, meta: &M, - create_vertex: impl Fn(Vec2, Vec3, Vec3, &M) -> O::Vertex, + create_vertex: impl Fn(Vec2, Vec3, Vec3, &M) -> O, ) -> Quad { Quad::new( create_vertex(atlas_pos, origin, norm, meta), diff --git a/voxygen/src/mesh/mod.rs b/voxygen/src/mesh/mod.rs index 657d635e32..b8c1ed8af9 100644 --- a/voxygen/src/mesh/mod.rs +++ b/voxygen/src/mesh/mod.rs @@ -2,25 +2,6 @@ pub mod greedy; pub mod segment; pub mod terrain; -use crate::render::{self, Mesh}; +use crate::render::Mesh; -pub type MeshGen = ( - Mesh<>::Pipeline>, - Mesh<>::TranslucentPipeline>, - Mesh<>::ShadowPipeline>, - >::Result, -); - -/// FIXME: Remove this whole trait at some point. This "abstraction" is never -/// abstracted over, and is organized completely differently from how we -/// actually mesh things nowadays. -pub trait Meshable { - type Pipeline: render::Pipeline; - type TranslucentPipeline: render::Pipeline; - type ShadowPipeline: render::Pipeline; - type Supplement; - type Result; - - // Generate meshes - one opaque, one translucent, one shadow - fn generate_mesh(self, supp: Self::Supplement) -> MeshGen; -} +pub type MeshGen = (Mesh, Mesh, Mesh, R); diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index eca4cc9d62..0de1b21701 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -1,12 +1,9 @@ use crate::{ mesh::{ greedy::{self, GreedyConfig, GreedyMesh}, - MeshGen, Meshable, - }, - render::{ - self, FigurePipeline, Mesh, ParticlePipeline, ShadowPipeline, SpritePipeline, - TerrainPipeline, + MeshGen, }, + render::{Mesh, ParticleVertex, SpriteVertex, TerrainVertex}, scene::math, }; use common::{ @@ -16,353 +13,315 @@ use common::{ use core::convert::TryFrom; use vek::*; -type SpriteVertex = ::Vertex; -type TerrainVertex = ::Vertex; -type ParticleVertex = ::Vertex; - -impl<'a: 'b, 'b, V: 'a> Meshable> for V -where - V: BaseVol + ReadVol + SizedVol, - /* TODO: Use VolIterator instead of manually iterating - * &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>, - * &'a V: BaseVol, */ -{ - type Pipeline = TerrainPipeline; - type Result = math::Aabb; - type ShadowPipeline = ShadowPipeline; - /// NOTE: bone_idx must be in [0, 15] (may be bumped to [0, 31] at some - /// point). - type Supplement = ( +// /// NOTE: bone_idx must be in [0, 15] (may be bumped to [0, 31] at some +// /// point). +#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 +// TODO: this function name... +pub fn generate_mesh_base_vol_terrain<'a: 'b, 'b, V: 'a>( + vol: V, + (greedy, opaque_mesh, offs, scale, bone_idx): ( &'b mut GreedyMesh<'a>, - &'b mut Mesh, + &'b mut Mesh, Vec3, Vec3, u8, - ); - type TranslucentPipeline = FigurePipeline; - - #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 - fn generate_mesh( - self, - (greedy, opaque_mesh, offs, scale, bone_idx): Self::Supplement, - ) -> MeshGen, Self> { - assert!(bone_idx <= 15, "Bone index for figures must be in [0, 15]"); - - let max_size = greedy.max_size(); - // NOTE: Required because we steal two bits from the normal in the shadow uint - // in order to store the bone index. The two bits are instead taken out - // of the atlas coordinates, which is why we "only" allow 1 << 15 per - // coordinate instead of 1 << 16. - assert!(max_size.width.max(max_size.height) < 1 << 15); - - let lower_bound = self.lower_bound(); - let upper_bound = self.upper_bound(); - assert!( - lower_bound.x <= upper_bound.x - && lower_bound.y <= upper_bound.y - && lower_bound.z <= upper_bound.z - ); - // NOTE: Figure sizes should be no more than 512 along each axis. - let greedy_size = upper_bound - lower_bound + 1; - assert!(greedy_size.x <= 512 && greedy_size.y <= 512 && greedy_size.z <= 512); - // NOTE: Cast to usize is safe because of previous check, since all values fit - // into u16 which is safe to cast to usize. - let greedy_size = greedy_size.as_::(); - let greedy_size_cross = greedy_size; - let draw_delta = lower_bound; - - let get_light = |vol: &mut V, pos: Vec3| { - if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) { - 1.0 - } else { - 0.0 - } - }; - let get_glow = |_vol: &mut V, _pos: Vec3| 0.0; - let get_opacity = - |vol: &mut V, pos: Vec3| vol.get(pos).map_or(true, |vox| vox.is_empty()); - let should_draw = |vol: &mut V, pos: Vec3, delta: Vec3, uv| { - should_draw_greedy(pos, delta, uv, |vox| { - vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty()) - }) - }; - let create_opaque = |atlas_pos, pos, norm| { - TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, bone_idx) - }; - - greedy.push(GreedyConfig { - data: self, - draw_delta, - greedy_size, - greedy_size_cross, - get_light, - get_glow, - get_opacity, - should_draw, - push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| { - opaque_mesh.push_quad(greedy::create_quad( - atlas_origin, - dim, - origin, - draw_dim, - norm, - meta, - |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), - )); - }, - make_face_texel: |vol: &mut V, pos, light, _| { - let cell = vol.get(pos).ok(); - let (glowy, shiny) = cell - .map(|c| (c.is_glowy(), c.is_shiny())) - .unwrap_or_default(); - let col = cell.and_then(|vox| vox.get_color()).unwrap_or(Rgb::zero()); - TerrainVertex::make_col_light_figure(light, glowy, shiny, col) - }, - }); - let bounds = math::Aabb { - // NOTE: Casts are safe since lower_bound and upper_bound both fit in a i16. - min: math::Vec3::from((lower_bound.as_::() + offs) * scale), - max: math::Vec3::from((upper_bound.as_::() + offs) * scale), - } - .made_valid(); - - (Mesh::new(), Mesh::new(), Mesh::new(), bounds) - } -} - -impl<'a: 'b, 'b, V: 'a> Meshable> for V + ), +) -> MeshGen> where V: BaseVol + ReadVol + SizedVol, - /* TODO: Use VolIterator instead of manually iterating - * &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>, - * &'a V: BaseVol, */ { - type Pipeline = SpritePipeline; - type Result = (); - type ShadowPipeline = ShadowPipeline; - type Supplement = (&'b mut GreedyMesh<'a>, &'b mut Mesh, bool); - type TranslucentPipeline = SpritePipeline; + assert!(bone_idx <= 15, "Bone index for figures must be in [0, 15]"); + let max_size = greedy.max_size(); + // NOTE: Required because we steal two bits from the normal in the shadow uint + // in order to store the bone index. The two bits are instead taken out + // of the atlas coordinates, which is why we "only" allow 1 << 15 per + // coordinate instead of 1 << 16. + assert!(max_size.width.max(max_size.height) < 1 << 15); - #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 - fn generate_mesh( - self, - (greedy, opaque_mesh, vertical_stripes): Self::Supplement, - ) -> MeshGen, Self> { - let max_size = greedy.max_size(); - // NOTE: Required because we steal two bits from the normal in the shadow uint - // in order to store the bone index. The two bits are instead taken out - // of the atlas coordinates, which is why we "only" allow 1 << 15 per - // coordinate instead of 1 << 16. - assert!(max_size.width.max(max_size.height) < 1 << 16); + let lower_bound = vol.lower_bound(); + let upper_bound = vol.upper_bound(); + assert!( + lower_bound.x <= upper_bound.x + && lower_bound.y <= upper_bound.y + && lower_bound.z <= upper_bound.z + ); + // NOTE: Figure sizes should be no more than 512 along each axis. + let greedy_size = upper_bound - lower_bound + 1; + assert!(greedy_size.x <= 512 && greedy_size.y <= 512 && greedy_size.z <= 512); + // NOTE: Cast to usize is safe because of previous check, since all values fit + // into u16 which is safe to cast to usize. + let greedy_size = greedy_size.as_::(); + let greedy_size_cross = greedy_size; + let draw_delta = lower_bound; - let lower_bound = self.lower_bound(); - let upper_bound = self.upper_bound(); - assert!( - lower_bound.x <= upper_bound.x - && lower_bound.y <= upper_bound.y - && lower_bound.z <= upper_bound.z - ); - // Lower bound coordinates must fit in an i16 (which means upper bound - // coordinates fit as integers in a f23). - assert!( - i16::try_from(lower_bound.x).is_ok() - && i16::try_from(lower_bound.y).is_ok() - && i16::try_from(lower_bound.z).is_ok(), - "Sprite offsets should fit in i16", - ); - let greedy_size = upper_bound - lower_bound + 1; - // TODO: Should this be 16, 16, 64? - assert!( - greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 64, - "Sprite size out of bounds: {:?} ≤ (31, 31, 63)", - greedy_size - 1 - ); + let get_light = |vol: &mut V, pos: Vec3| { + if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) { + 1.0 + } else { + 0.0 + } + }; + let get_glow = |_vol: &mut V, _pos: Vec3| 0.0; + let get_opacity = |vol: &mut V, pos: Vec3| vol.get(pos).map_or(true, |vox| vox.is_empty()); + let should_draw = |vol: &mut V, pos: Vec3, delta: Vec3, uv| { + should_draw_greedy(pos, delta, uv, |vox| { + vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty()) + }) + }; + let create_opaque = |atlas_pos, pos, norm| { + TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, bone_idx) + }; - let (flat, flat_get) = { - let (w, h, d) = (greedy_size + 2).into_tuple(); - let flat = { - let vol = self; + greedy.push(GreedyConfig { + data: vol, + draw_delta, + greedy_size, + greedy_size_cross, + get_light, + get_glow, + get_opacity, + should_draw, + push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| { + opaque_mesh.push_quad(greedy::create_quad( + atlas_origin, + dim, + origin, + draw_dim, + norm, + meta, + |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), + )); + }, + make_face_texel: |vol: &mut V, pos, light, _| { + let cell = vol.get(pos).ok(); + let (glowy, shiny) = cell + .map(|c| (c.is_glowy(), c.is_shiny())) + .unwrap_or_default(); + let col = cell.and_then(|vox| vox.get_color()).unwrap_or(Rgb::zero()); + TerrainVertex::make_col_light_figure(light, glowy, shiny, col) + }, + }); + let bounds = math::Aabb { + // NOTE: Casts are safe since lower_bound and upper_bound both fit in a i16. + min: math::Vec3::from((lower_bound.as_::() + offs) * scale), + max: math::Vec3::from((upper_bound.as_::() + offs) * scale), + } + .made_valid(); - let mut flat = vec![Cell::empty(); (w * h * d) as usize]; - let mut i = 0; - for x in -1..greedy_size.x + 1 { - for y in -1..greedy_size.y + 1 { - for z in -1..greedy_size.z + 1 { - let wpos = lower_bound + Vec3::new(x, y, z); - let block = vol.get(wpos).map(|b| *b).unwrap_or(Cell::empty()); - flat[i] = block; - i += 1; - } + (Mesh::new(), Mesh::new(), Mesh::new(), bounds) +} + +#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 +pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>( + vol: V, + (greedy, opaque_mesh, vertical_stripes): ( + &'b mut GreedyMesh<'a>, + &'b mut Mesh, + bool, + ), +) -> MeshGen +where + V: BaseVol + ReadVol + SizedVol, +{ + let max_size = greedy.max_size(); + // NOTE: Required because we steal two bits from the normal in the shadow uint + // in order to store the bone index. The two bits are instead taken out + // of the atlas coordinates, which is why we "only" allow 1 << 15 per + // coordinate instead of 1 << 16. + assert!(max_size.width.max(max_size.height) < 1 << 16); + + let lower_bound = vol.lower_bound(); + let upper_bound = vol.upper_bound(); + assert!( + lower_bound.x <= upper_bound.x + && lower_bound.y <= upper_bound.y + && lower_bound.z <= upper_bound.z + ); + // Lower bound coordinates must fit in an i16 (which means upper bound + // coordinates fit as integers in a f23). + assert!( + i16::try_from(lower_bound.x).is_ok() + && i16::try_from(lower_bound.y).is_ok() + && i16::try_from(lower_bound.z).is_ok(), + "Sprite offsets should fit in i16", + ); + let greedy_size = upper_bound - lower_bound + 1; + // TODO: Should this be 16, 16, 64? + assert!( + greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 64, + "Sprite size out of bounds: {:?} ≤ (31, 31, 63)", + greedy_size - 1 + ); + + let (flat, flat_get) = { + let (w, h, d) = (greedy_size + 2).into_tuple(); + let flat = { + let mut flat = vec![Cell::empty(); (w * h * d) as usize]; + let mut i = 0; + for x in -1..greedy_size.x + 1 { + for y in -1..greedy_size.y + 1 { + for z in -1..greedy_size.z + 1 { + let wpos = lower_bound + Vec3::new(x, y, z); + let block = vol.get(wpos).map(|b| *b).unwrap_or(Cell::empty()); + flat[i] = block; + i += 1; } } - flat - }; - - let flat_get = move |flat: &Vec, Vec3 { x, y, z }| match flat - .get((x * h * d + y * d + z) as usize) - .copied() - { - Some(b) => b, - None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h), - }; - - (flat, flat_get) - }; - - // NOTE: Cast to usize is safe because of previous check, since all values fit - // into u16 which is safe to cast to usize. - let greedy_size = greedy_size.as_::(); - - let greedy_size_cross = greedy_size; - let draw_delta = Vec3::new(1, 1, 1); - - let get_light = move |flat: &mut _, pos: Vec3| { - if flat_get(flat, pos).is_empty() { - 1.0 - } else { - 0.0 } - }; - let get_glow = |_flat: &mut _, _pos: Vec3| 0.0; - let get_color = move |flat: &mut _, pos: Vec3| { - flat_get(flat, pos).get_color().unwrap_or(Rgb::zero()) - }; - let get_opacity = move |flat: &mut _, pos: Vec3| flat_get(flat, pos).is_empty(); - let should_draw = move |flat: &mut _, pos: Vec3, delta: Vec3, uv| { - should_draw_greedy_ao(vertical_stripes, pos, delta, uv, |vox| flat_get(flat, vox)) - }; - // NOTE: Fits in i16 (much lower actually) so f32 is no problem (and the final - // position, pos + mesh_delta, is guaranteed to fit in an f32). - let mesh_delta = lower_bound.as_::(); - let create_opaque = |atlas_pos, pos: Vec3, norm, _meta| { - SpriteVertex::new(atlas_pos, pos + mesh_delta, norm) + flat }; - greedy.push(GreedyConfig { - data: flat, - draw_delta, - greedy_size, - greedy_size_cross, - get_light, - get_glow, - get_opacity, - should_draw, - push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &bool| { - opaque_mesh.push_quad(greedy::create_quad( - atlas_origin, - dim, - origin, - draw_dim, - norm, - meta, - |atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta), - )); - }, - make_face_texel: move |flat: &mut _, pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(flat, pos)) - }, - }); + let flat_get = move |flat: &Vec, Vec3 { x, y, z }| match flat + .get((x * h * d + y * d + z) as usize) + .copied() + { + Some(b) => b, + None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h), + }; - (Mesh::new(), Mesh::new(), Mesh::new(), ()) - } + (flat, flat_get) + }; + + // NOTE: Cast to usize is safe because of previous check, since all values fit + // into u16 which is safe to cast to usize. + let greedy_size = greedy_size.as_::(); + + let greedy_size_cross = greedy_size; + let draw_delta = Vec3::new(1, 1, 1); + + let get_light = move |flat: &mut _, pos: Vec3| { + if flat_get(flat, pos).is_empty() { + 1.0 + } else { + 0.0 + } + }; + let get_glow = |_flat: &mut _, _pos: Vec3| 0.0; + let get_color = + move |flat: &mut _, pos: Vec3| flat_get(flat, pos).get_color().unwrap_or(Rgb::zero()); + let get_opacity = move |flat: &mut _, pos: Vec3| flat_get(flat, pos).is_empty(); + let should_draw = move |flat: &mut _, pos: Vec3, delta: Vec3, uv| { + should_draw_greedy_ao(vertical_stripes, pos, delta, uv, |vox| flat_get(flat, vox)) + }; + // NOTE: Fits in i16 (much lower actually) so f32 is no problem (and the final + // position, pos + mesh_delta, is guaranteed to fit in an f32). + let mesh_delta = lower_bound.as_::(); + let create_opaque = |atlas_pos, pos: Vec3, norm, _meta| { + SpriteVertex::new(atlas_pos, pos + mesh_delta, norm) + }; + + greedy.push(GreedyConfig { + data: flat, + draw_delta, + greedy_size, + greedy_size_cross, + get_light, + get_glow, + get_opacity, + should_draw, + push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &bool| { + opaque_mesh.push_quad(greedy::create_quad( + atlas_origin, + dim, + origin, + draw_dim, + norm, + meta, + |atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta), + )); + }, + make_face_texel: move |flat: &mut _, pos, light, glow| { + TerrainVertex::make_col_light(light, glow, get_color(flat, pos)) + }, + }); + + (Mesh::new(), Mesh::new(), Mesh::new(), ()) } -impl<'a: 'b, 'b, V: 'a> Meshable> for V +#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 +pub fn generate_mesh_base_vol_particle<'a: 'b, 'b, V: 'a>( + vol: V, + greedy: &'b mut GreedyMesh<'a>, +) -> MeshGen where V: BaseVol + ReadVol + SizedVol, - /* TODO: Use VolIterator instead of manually iterating - * &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>, - * &'a V: BaseVol, */ { - type Pipeline = ParticlePipeline; - type Result = (); - type ShadowPipeline = ShadowPipeline; - type Supplement = &'b mut GreedyMesh<'a>; - type TranslucentPipeline = ParticlePipeline; + let max_size = greedy.max_size(); + // NOTE: Required because we steal two bits from the normal in the shadow uint + // in order to store the bone index. The two bits are instead taken out + // of the atlas coordinates, which is why we "only" allow 1 << 15 per + // coordinate instead of 1 << 16. + assert!(max_size.width.max(max_size.height) < 1 << 16); - #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 - fn generate_mesh( - self, - greedy: Self::Supplement, - ) -> MeshGen, Self> { - let max_size = greedy.max_size(); - // NOTE: Required because we steal two bits from the normal in the shadow uint - // in order to store the bone index. The two bits are instead taken out - // of the atlas coordinates, which is why we "only" allow 1 << 15 per - // coordinate instead of 1 << 16. - assert!(max_size.width.max(max_size.height) < 1 << 16); + let lower_bound = vol.lower_bound(); + let upper_bound = vol.upper_bound(); + assert!( + lower_bound.x <= upper_bound.x + && lower_bound.y <= upper_bound.y + && lower_bound.z <= upper_bound.z + ); + let greedy_size = upper_bound - lower_bound + 1; + assert!( + greedy_size.x <= 16 && greedy_size.y <= 16 && greedy_size.z <= 64, + "Particle size out of bounds: {:?} ≤ (15, 15, 63)", + greedy_size - 1 + ); + // NOTE: Cast to usize is safe because of previous check, since all values fit + // into u16 which is safe to cast to usize. + let greedy_size = greedy_size.as_::(); - let lower_bound = self.lower_bound(); - let upper_bound = self.upper_bound(); - assert!( - lower_bound.x <= upper_bound.x - && lower_bound.y <= upper_bound.y - && lower_bound.z <= upper_bound.z - ); - let greedy_size = upper_bound - lower_bound + 1; - assert!( - greedy_size.x <= 16 && greedy_size.y <= 16 && greedy_size.z <= 64, - "Particle size out of bounds: {:?} ≤ (15, 15, 63)", - greedy_size - 1 - ); - // NOTE: Cast to usize is safe because of previous check, since all values fit - // into u16 which is safe to cast to usize. - let greedy_size = greedy_size.as_::(); + let greedy_size_cross = greedy_size; + let draw_delta = lower_bound; - let greedy_size_cross = greedy_size; - let draw_delta = lower_bound; + let get_light = |vol: &mut V, pos: Vec3| { + if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) { + 1.0 + } else { + 0.0 + } + }; + let get_glow = |_vol: &mut V, _pos: Vec3| 0.0; + let get_color = |vol: &mut V, pos: Vec3| { + vol.get(pos) + .ok() + .and_then(|vox| vox.get_color()) + .unwrap_or(Rgb::zero()) + }; + let get_opacity = |vol: &mut V, pos: Vec3| vol.get(pos).map_or(true, |vox| vox.is_empty()); + let should_draw = |vol: &mut V, pos: Vec3, delta: Vec3, uv| { + should_draw_greedy(pos, delta, uv, |vox| { + vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty()) + }) + }; + let create_opaque = |_atlas_pos, pos: Vec3, norm| ParticleVertex::new(pos, norm); - let get_light = |vol: &mut V, pos: Vec3| { - if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) { - 1.0 - } else { - 0.0 - } - }; - let get_glow = |_vol: &mut V, _pos: Vec3| 0.0; - let get_color = |vol: &mut V, pos: Vec3| { - vol.get(pos) - .ok() - .and_then(|vox| vox.get_color()) - .unwrap_or(Rgb::zero()) - }; - let get_opacity = - |vol: &mut V, pos: Vec3| vol.get(pos).map_or(true, |vox| vox.is_empty()); - let should_draw = |vol: &mut V, pos: Vec3, delta: Vec3, uv| { - should_draw_greedy(pos, delta, uv, |vox| { - vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty()) - }) - }; - let create_opaque = |_atlas_pos, pos: Vec3, norm| ParticleVertex::new(pos, norm); + let mut opaque_mesh = Mesh::new(); + greedy.push(GreedyConfig { + data: vol, + draw_delta, + greedy_size, + greedy_size_cross, + get_light, + get_glow, + get_opacity, + should_draw, + push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| { + opaque_mesh.push_quad(greedy::create_quad( + atlas_origin, + dim, + origin, + draw_dim, + norm, + meta, + |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), + )); + }, + make_face_texel: move |vol: &mut V, pos, light, glow| { + TerrainVertex::make_col_light(light, glow, get_color(vol, pos)) + }, + }); - let mut opaque_mesh = Mesh::new(); - greedy.push(GreedyConfig { - data: self, - draw_delta, - greedy_size, - greedy_size_cross, - get_light, - get_glow, - get_opacity, - should_draw, - push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| { - opaque_mesh.push_quad(greedy::create_quad( - atlas_origin, - dim, - origin, - draw_dim, - norm, - meta, - |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), - )); - }, - make_face_texel: move |vol: &mut V, pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(vol, pos)) - }, - }); - - (opaque_mesh, Mesh::new(), Mesh::new(), ()) - } + (opaque_mesh, Mesh::new(), Mesh::new(), ()) } fn should_draw_greedy( diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 682e798dd6..db25d67d36 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -3,9 +3,9 @@ use crate::{ mesh::{ greedy::{self, GreedyConfig, GreedyMesh}, - MeshGen, Meshable, + MeshGen, }, - render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline}, + render::{ColLightInfo, FluidVertex, Mesh, TerrainVertex}, scene::terrain::BlocksOfInterest, }; use common::{ @@ -19,9 +19,6 @@ use std::{collections::VecDeque, fmt::Debug, sync::Arc}; use tracing::error; use vek::*; -type TerrainVertex = ::Vertex; -type FluidVertex = ::Vertex; - #[derive(Clone, Copy, PartialEq)] enum FaceKind { /// Opaque face that is facing something non-opaque; either @@ -227,243 +224,234 @@ fn calc_light + ReadVol + Debug>( } } -impl<'a, V: RectRasterableVol + ReadVol + Debug + 'static> - Meshable for &'a VolGrid2d -{ - type Pipeline = TerrainPipeline; - #[allow(clippy::type_complexity)] - type Result = ( +#[allow(clippy::collapsible_if)] +#[allow(clippy::many_single_char_names)] +#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587 +#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 +pub fn generate_mesh<'a, V: RectRasterableVol + ReadVol + Debug + 'static>( + vol: &'a VolGrid2d, + (range, max_texture_size): (Aabb, Vec2), + (range, max_texture_size, _boi): (Aabb, Vec2, &'a BlocksOfInterest), +) -> MeshGen< + TerrainVertex, + FluidVertex, + TerrainVertex, + ( Aabb, ColLightInfo, Arc) -> f32 + Send + Sync>, Arc) -> f32 + Send + Sync>, + ), +> { + span!( + _guard, + "generate_mesh", + "<&VolGrid2d as Meshable<_, _>>::generate_mesh" ); - type ShadowPipeline = ShadowPipeline; - type Supplement = (Aabb, Vec2, &'a BlocksOfInterest); - type TranslucentPipeline = FluidPipeline; - #[allow(clippy::collapsible_if)] - #[allow(clippy::many_single_char_names)] - #[allow(clippy::needless_range_loop)] // TODO: Pending review in #587 - #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 - fn generate_mesh( - self, - (range, max_texture_size, _boi): Self::Supplement, - ) -> MeshGen { - span!( - _guard, - "generate_mesh", - "<&VolGrid2d as Meshable<_, _>>::generate_mesh" - ); + // Find blocks that should glow + // TODO: Search neighbouring chunks too! + // let glow_blocks = boi.lights + // .iter() + // .map(|(pos, glow)| (*pos + range.min.xy(), *glow)); + /* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST) + .filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */ - // Find blocks that should glow - // TODO: Search neighbouring chunks too! - // let glow_blocks = boi.lights - // .iter() - // .map(|(pos, glow)| (*pos + range.min.xy(), *glow)); - /* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST) - .filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */ + let mut glow_blocks = Vec::new(); - let mut glow_blocks = Vec::new(); - - // TODO: This expensive, use BlocksOfInterest instead - let mut volume = self.cached(); - for x in -MAX_LIGHT_DIST..range.size().w + MAX_LIGHT_DIST { - for y in -MAX_LIGHT_DIST..range.size().h + MAX_LIGHT_DIST { - for z in -1..range.size().d + 1 { - let wpos = range.min + Vec3::new(x, y, z); - volume - .get(wpos) - .ok() - .and_then(|b| b.get_glow()) - .map(|glow| glow_blocks.push((wpos, glow))); - } + // TODO: This expensive, use BlocksOfInterest instead + let mut volume = self.cached(); + for x in -MAX_LIGHT_DIST..range.size().w + MAX_LIGHT_DIST { + for y in -MAX_LIGHT_DIST..range.size().h + MAX_LIGHT_DIST { + for z in -1..range.size().d + 1 { + let wpos = range.min + Vec3::new(x, y, z); + volume + .get(wpos) + .ok() + .and_then(|b| b.get_glow()) + .map(|glow| glow_blocks.push((wpos, glow))); } } + } - // Calculate chunk lighting (sunlight defaults to 1.0, glow to 0.0) - let light = calc_light(true, SUNLIGHT, range, self, core::iter::empty()); - let glow = calc_light(false, 0, range, self, glow_blocks.into_iter()); + // Calculate chunk lighting (sunlight defaults to 1.0, glow to 0.0) + let light = calc_light(true, SUNLIGHT, range, self, core::iter::empty()); + let glow = calc_light(false, 0, range, self, glow_blocks.into_iter()); - let mut opaque_limits = None::; - let mut fluid_limits = None::; - let mut air_limits = None::; - let flat_get = { - span!(_guard, "copy to flat array"); - let (w, h, d) = range.size().into_tuple(); - // z can range from -1..range.size().d + 1 - let d = d + 2; - let flat = { - let mut volume = self.cached(); - - const AIR: Block = Block::air(common::terrain::sprite::SpriteKind::Empty); - - // TODO: Once we can manage it sensibly, consider using something like - // Option instead of just assuming air. - let mut flat = vec![AIR; (w * h * d) as usize]; - let mut i = 0; - for x in 0..range.size().w { - for y in 0..range.size().h { - for z in -1..range.size().d + 1 { - let wpos = range.min + Vec3::new(x, y, z); - let block = volume - .get(wpos) - .map(|b| *b) - // TODO: Replace with None or some other more reasonable value, - // since it's not clear this will work properly with liquid. - .unwrap_or(AIR); - if block.is_opaque() { - opaque_limits = opaque_limits - .map(|l| l.including(z)) - .or_else(|| Some(Limits::from_value(z))); - } else if block.is_liquid() { - fluid_limits = fluid_limits - .map(|l| l.including(z)) - .or_else(|| Some(Limits::from_value(z))); - } else { - // Assume air - air_limits = air_limits - .map(|l| l.including(z)) - .or_else(|| Some(Limits::from_value(z))); - }; - flat[i] = block; - i += 1; - } + let mut opaque_limits = None::; + let mut fluid_limits = None::; + let mut air_limits = None::; + let flat_get = { + span!(_guard, "copy to flat array"); + let (w, h, d) = range.size().into_tuple(); + // z can range from -1..range.size().d + 1 + let d = d + 2; + let flat = { + let mut volume = vol.cached(); + const AIR: Block = Block::air(common::terrain::sprite::SpriteKind::Empty); + // TODO: Once we can manage it sensibly, consider using something like + // Option instead of just assuming air. + let mut flat = vec![AIR; (w * h * d) as usize]; + let mut i = 0; + for x in 0..range.size().w { + for y in 0..range.size().h { + for z in -1..range.size().d + 1 { + let wpos = range.min + Vec3::new(x, y, z); + let block = volume + .get(wpos) + .map(|b| *b) + // TODO: Replace with None or some other more reasonable value, + // since it's not clear this will work properly with liquid. + .unwrap_or(AIR); + if block.is_opaque() { + opaque_limits = opaque_limits + .map(|l| l.including(z)) + .or_else(|| Some(Limits::from_value(z))); + } else if block.is_liquid() { + fluid_limits = fluid_limits + .map(|l| l.including(z)) + .or_else(|| Some(Limits::from_value(z))); + } else { + // Assume air + air_limits = air_limits + .map(|l| l.including(z)) + .or_else(|| Some(Limits::from_value(z))); + }; + flat[i] = block; + i += 1; } } - flat - }; - - move |Vec3 { x, y, z }| { - // z can range from -1..range.size().d + 1 - let z = z + 1; - match flat.get((x * h * d + y * d + z) as usize).copied() { - Some(b) => b, - None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h), - } } + flat }; - // Constrain iterated area - let (z_start, z_end) = match (air_limits, fluid_limits, opaque_limits) { - (Some(air), Some(fluid), Some(opaque)) => air.three_way_intersection(fluid, opaque), - (Some(air), Some(fluid), None) => air.intersection(fluid), - (Some(air), None, Some(opaque)) => air.intersection(opaque), - (None, Some(fluid), Some(opaque)) => fluid.intersection(opaque), - // No interfaces (Note: if there are multiple fluid types this could change) - (Some(_), None, None) | (None, Some(_), None) | (None, None, Some(_)) => None, - (None, None, None) => { - error!("Impossible unless given an input AABB that has a height of zero"); - None - }, + move |Vec3 { x, y, z }| { + // z can range from -1..range.size().d + 1 + let z = z + 1; + match flat.get((x * h * d + y * d + z) as usize).copied() { + Some(b) => b, + None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h), + } } - .map_or((0, 0), |limits| { - let (start, end) = limits.into_tuple(); - let start = start.max(0); - let end = end.min(range.size().d - 1).max(start); - (start, end) - }); + }; - let max_size = - guillotiere::Size::new(i32::from(max_texture_size.x), i32::from(max_texture_size.y)); - assert!(z_end >= z_start); - let greedy_size = Vec3::new(range.size().w - 2, range.size().h - 2, z_end - z_start + 1); - // NOTE: Terrain sizes are limited to 32 x 32 x 16384 (to fit in 24 bits: 5 + 5 - // + 14). FIXME: Make this function fallible, since the terrain - // information might be dynamically generated which would make this hard - // to enforce. - assert!(greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 16384); - // NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16, - // which always fits into a f32. - let max_bounds: Vec3 = greedy_size.as_::(); - // NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16, - // which always fits into a usize. - let greedy_size = greedy_size.as_::(); - let greedy_size_cross = Vec3::new(greedy_size.x - 1, greedy_size.y - 1, greedy_size.z); - let draw_delta = Vec3::new(1, 1, z_start); - - let get_light = |_: &mut (), pos: Vec3| { - if flat_get(pos).is_opaque() { - 0.0 - } else { - light(pos + range.min) - } - }; - let get_glow = |_: &mut (), pos: Vec3| glow(pos + range.min); - let get_color = - |_: &mut (), pos: Vec3| flat_get(pos).get_color().unwrap_or(Rgb::zero()); - let get_opacity = |_: &mut (), pos: Vec3| !flat_get(pos).is_opaque(); - let flat_get = |pos| flat_get(pos); - let should_draw = |_: &mut (), pos: Vec3, delta: Vec3, _uv| { - should_draw_greedy(pos, delta, flat_get) - }; - // NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16. - let mesh_delta = Vec3::new(0.0, 0.0, (z_start + range.min.z) as f32); - let create_opaque = |atlas_pos, pos, norm, meta| { - TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta) - }; - let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm); - - let mut greedy = GreedyMesh::new(max_size); - let mut opaque_mesh = Mesh::new(); - let mut fluid_mesh = Mesh::new(); - greedy.push(GreedyConfig { - data: (), - draw_delta, - greedy_size, - greedy_size_cross, - get_light, - get_glow, - get_opacity, - should_draw, - push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta { - FaceKind::Opaque(meta) => { - opaque_mesh.push_quad(greedy::create_quad( - atlas_origin, - dim, - origin, - draw_dim, - norm, - meta, - |atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta), - )); - }, - FaceKind::Fluid => { - fluid_mesh.push_quad(greedy::create_quad( - atlas_origin, - dim, - origin, - draw_dim, - norm, - &(), - |atlas_pos, pos, norm, &_meta| create_transparent(atlas_pos, pos, norm), - )); - }, - }, - make_face_texel: |data: &mut (), pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(data, pos)) - }, - }); - - let min_bounds = mesh_delta; - let bounds = Aabb { - min: min_bounds, - max: max_bounds + min_bounds, - }; - let (col_lights, col_lights_size) = greedy.finalize(); - - ( - opaque_mesh, - fluid_mesh, - Mesh::new(), - ( - bounds, - (col_lights, col_lights_size), - Arc::new(light), - Arc::new(glow), - ), - ) + // Constrain iterated area + let (z_start, z_end) = match (air_limits, fluid_limits, opaque_limits) { + (Some(air), Some(fluid), Some(opaque)) => air.three_way_intersection(fluid, opaque), + (Some(air), Some(fluid), None) => air.intersection(fluid), + (Some(air), None, Some(opaque)) => air.intersection(opaque), + (None, Some(fluid), Some(opaque)) => fluid.intersection(opaque), + // No interfaces (Note: if there are multiple fluid types this could change) + (Some(_), None, None) | (None, Some(_), None) | (None, None, Some(_)) => None, + (None, None, None) => { + error!("Impossible unless given an input AABB that has a height of zero"); + None + }, } + .map_or((0, 0), |limits| { + let (start, end) = limits.into_tuple(); + let start = start.max(0); + let end = end.min(range.size().d - 1).max(start); + (start, end) + }); + + let max_size = + guillotiere::Size::new(i32::from(max_texture_size.x), i32::from(max_texture_size.y)); + assert!(z_end >= z_start); + let greedy_size = Vec3::new(range.size().w - 2, range.size().h - 2, z_end - z_start + 1); + // NOTE: Terrain sizes are limited to 32 x 32 x 16384 (to fit in 24 bits: 5 + 5 + // + 14). FIXME: Make this function fallible, since the terrain + // information might be dynamically generated which would make this hard + // to enforce. + assert!(greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 16384); + // NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16, + // which always fits into a f32. + let max_bounds: Vec3 = greedy_size.as_::(); + // NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16, + // which always fits into a usize. + let greedy_size = greedy_size.as_::(); + let greedy_size_cross = Vec3::new(greedy_size.x - 1, greedy_size.y - 1, greedy_size.z); + let draw_delta = Vec3::new(1, 1, z_start); + + let get_light = |_: &mut (), pos: Vec3| { + if flat_get(pos).is_opaque() { + 0.0 + } else { + light(pos + range.min) + } + }; + let get_glow = |_: &mut (), pos: Vec3| glow(pos + range.min); + let get_color = |_: &mut (), pos: Vec3| flat_get(pos).get_color().unwrap_or(Rgb::zero()); + let get_opacity = |_: &mut (), pos: Vec3| !flat_get(pos).is_opaque(); + let flat_get = |pos| flat_get(pos); + let should_draw = |_: &mut (), pos: Vec3, delta: Vec3, _uv| { + should_draw_greedy(pos, delta, flat_get) + }; + // NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16. + let mesh_delta = Vec3::new(0.0, 0.0, (z_start + range.min.z) as f32); + let create_opaque = + |atlas_pos, pos, norm, meta| TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta); + let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm); + + let mut greedy = GreedyMesh::new(max_size); + let mut opaque_mesh = Mesh::new(); + let mut fluid_mesh = Mesh::new(); + greedy.push(GreedyConfig { + data: (), + draw_delta, + greedy_size, + greedy_size_cross, + get_light, + get_glow, + get_opacity, + should_draw, + push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta { + FaceKind::Opaque(meta) => { + opaque_mesh.push_quad(greedy::create_quad( + atlas_origin, + dim, + origin, + draw_dim, + norm, + meta, + |atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta), + )); + }, + FaceKind::Fluid => { + fluid_mesh.push_quad(greedy::create_quad( + atlas_origin, + dim, + origin, + draw_dim, + norm, + &(), + |atlas_pos, pos, norm, &_meta| create_transparent(atlas_pos, pos, norm), + )); + }, + }, + make_face_texel: |data: &mut (), pos, light, glow| { + TerrainVertex::make_col_light(light, glow, get_color(data, pos)) + }, + }); + + let min_bounds = mesh_delta; + let bounds = Aabb { + min: min_bounds, + max: max_bounds + min_bounds, + }; + let (col_lights, col_lights_size) = greedy.finalize(); + + ( + opaque_mesh, + fluid_mesh, + Mesh::new(), + ( + bounds, + (col_lights, col_lights_size), + Arc::new(light), + Arc::new(glow), + ), + ) } /// NOTE: Make sure to reflect any changes to how meshing is performanced in diff --git a/voxygen/src/render/buffer.rs b/voxygen/src/render/buffer.rs index 4bf1209784..5f1ad7058a 100644 --- a/voxygen/src/render/buffer.rs +++ b/voxygen/src/render/buffer.rs @@ -1,7 +1,6 @@ use bytemuck::Pod; use wgpu::util::DeviceExt; -#[derive(Clone)] pub struct Buffer { pub buf: wgpu::Buffer, // bytes @@ -10,7 +9,7 @@ pub struct Buffer { } impl Buffer { - pub fn new(device: &mut wgpu::Device, cap: usize, usage: wgpu::BufferUsage) -> Self { + pub fn new(device: &wgpu::Device, cap: u64, usage: wgpu::BufferUsage) -> Self { Self { buf: device.create_buffer(&wgpu::BufferDescriptor { label: None, @@ -23,8 +22,8 @@ impl Buffer { } } - pub fn new_with_data(device: &mut wgpu::Device, usage: wgpu::BufferUsage, data: &[T]) -> Self { - let contents = data.as_bytes(); + pub fn new_with_data(device: &wgpu::Device, usage: wgpu::BufferUsage, data: &[T]) -> Self { + let contents = bytemuck::cast_slice(data); Self { buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor { @@ -37,15 +36,9 @@ impl Buffer { } } - pub fn update( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - vals: &[T], - offset: usize, - ) { + pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) { if !vals.is_empty() { - queue.write_buffer(&self.buf, offset, vals.as_bytes()) + queue.write_buffer(&self.buf, offset, bytemuck::cast_slice(vals)) } } diff --git a/voxygen/src/render/consts.rs b/voxygen/src/render/consts.rs index d851bdaeba..e1c28b7e43 100644 --- a/voxygen/src/render/consts.rs +++ b/voxygen/src/render/consts.rs @@ -4,29 +4,22 @@ use bytemuck::Pod; /// A handle to a series of constants sitting on the GPU. This is used to hold /// information used in the rendering process that does not change throughout a /// single render pass. -#[derive(Clone)] pub struct Consts { buf: Buffer, } impl Consts { /// Create a new `Const`. - pub fn new(device: &mut wgpu::Device, len: usize) -> Self { + pub fn new(device: &wgpu::Device, len: u64) -> Self { Self { buf: Buffer::new(device, len, wgpu::BufferUsage::UNIFORM), } } /// Update the GPU-side value represented by this constant handle. - pub fn update( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - vals: &[T], - offset: usize, - ) { + pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) { self.buf.update(device, queue, vals, offset) } - pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf } + pub fn buf(&self) -> &wgpu::Buffer { &self.buf.buf } } diff --git a/voxygen/src/render/instances.rs b/voxygen/src/render/instances.rs index 02b0792e8b..a178b44f71 100644 --- a/voxygen/src/render/instances.rs +++ b/voxygen/src/render/instances.rs @@ -1,14 +1,13 @@ -use super::{buffer::Buffer, RenderError}; +use super::buffer::Buffer; use bytemuck::Pod; /// Represents a mesh that has been sent to the GPU. -#[derive(Clone)] pub struct Instances { buf: Buffer, } impl Instances { - pub fn new(device: &mut wgpu::Device, len: usize) -> Self { + pub fn new(device: &wgpu::Device, len: u64) -> Self { Self { buf: Buffer::new(device, len, wgpu::BufferUsage::VERTEX), } @@ -16,15 +15,9 @@ impl Instances { pub fn count(&self) -> usize { self.buf.count() } - pub fn update( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - vals: &[T], - offset: usize, - ) -> Result<(), RenderError> { + pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) { self.buf.update(device, queue, vals, offset) } - pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf } + pub fn buf(&self) -> &wgpu::Buffer { &self.buf.buf } } diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index c2d86441a5..3657de15df 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -1,4 +1,4 @@ -use super::{buffer::Buffer, mesh::Mesh, RenderError, Vertex}; +use super::{buffer::Buffer, mesh::Mesh, Vertex}; use std::ops::Range; /// Represents a mesh that has been sent to the GPU. @@ -24,7 +24,7 @@ impl Model { } } - pub fn new_dynamic(device: &wgpu::Device, size: usize) -> Self { + pub fn new_dynamic(device: &wgpu::Device, size: u64) -> Self { Self { vbuf: Buffer::new(device, size, wgpu::BufferUsage::VERTEX), } @@ -45,10 +45,10 @@ impl Model { device: &wgpu::Device, queue: &wgpu::Queue, mesh: &Mesh, - offset: usize, - ) -> Result<(), RenderError> { - self.buf.update(device, queue, mesh.vertices(), offset) + offset: u64, + ) { + self.vbuf.update(device, queue, mesh.vertices(), offset) } - pub fn buf(&self) -> &wgpu::Buffer { self.vbuf.buf } + pub fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf } } diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index 7f77235597..6dd6a65c5b 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -3,11 +3,11 @@ use super::{ terrain::Vertex, }; use crate::mesh::greedy::GreedyMesh; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { model_mat: [[f32; 4]; 4], highlight_col: [f32; 4], @@ -19,7 +19,7 @@ pub struct Locals { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct BoneData { bone_mat: [[f32; 4]; 4], normals_mat: [[f32; 4]; 4], diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index a7356d3af7..1ab92a6306 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -1,9 +1,9 @@ use super::super::{AaMode, GlobalsLayouts}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos_norm: u32, } diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index 501e89afc6..946ffa2f83 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -1,9 +1,9 @@ use super::super::{AaMode, GlobalsLayouts, Renderer, Texture}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos: [f32; 2], } @@ -39,7 +39,7 @@ pub struct LodData { impl LodData { pub fn new( renderer: &mut Renderer, - map_size: Vec2, + map_size: Vec2, lod_base: &[u32], lod_alt: &[u32], lod_horizon: &[u32], @@ -72,28 +72,41 @@ impl LodData { ..Default::default() }; + let mut view_info = wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }; + let map = renderer.create_texture_with_data_raw( &texture_info, + &view_info, &sampler_info, map_size.x * 4, - [map_size.x, map_size.y], - lod_base.as_bytes(), + bytemuck::cast_slice(lod_base), ); - texture_info = wgpu::TextureFormat::Rg16Uint; + texture_info.format = wgpu::TextureFormat::Rg16Uint; + view_info.format = Some(wgpu::TextureFormat::Rg16Uint); let alt = renderer.create_texture_with_data_raw( &texture_info, + &view_info, &sampler_info, map_size.x * 4, - [map_size.x, map_size.y], - lod_base.as_bytes(), + bytemuck::cast_slice(lod_base), ); - texture_info = wgpu::TextureFormat::Rgba8Unorm; + texture_info.format = wgpu::TextureFormat::Rgba8Unorm; + view_info.format = Some(wgpu::TextureFormat::Rg16Uint); let horizon = renderer.create_texture_with_data_raw( &texture_info, + &view_info, &sampler_info, map_size.x * 4, - [map_size.x, map_size.y], - lod_base.as_bytes(), + bytemuck::cast_slice(lod_base), ); Self { diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 226ab3ec50..49718f3630 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -12,7 +12,7 @@ pub mod ui; use super::Consts; use crate::scene::camera::CameraMode; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use common::terrain::BlockKind; use vek::*; @@ -21,7 +21,7 @@ pub const MAX_FIGURE_SHADOW_COUNT: usize = 24; pub const MAX_DIRECTED_LIGHT_COUNT: usize = 6; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Globals { view_mat: [[f32; 4]; 4], proj_mat: [[f32; 4]; 4], @@ -55,14 +55,14 @@ pub struct Globals { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Light { - pos: [f32; 4], - col: [f32; 4], + pub pos: [f32; 4], + pub col: [f32; 4], } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Shadow { pos_radius: [f32; 4], } diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index bfe05d554f..eeebc7d1dd 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -1,9 +1,9 @@ use super::super::{AaMode, GlobalsLayouts}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos: [f32; 3], // ____BBBBBBBBGGGGGGGGRRRRRRRR @@ -79,7 +79,7 @@ impl ParticleMode { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Instance { // created_at time, so we can calculate time relativity, needed for relative animation. // can save 32 bits per instance, for particles that are not relatively animated. diff --git a/voxygen/src/render/pipelines/postprocess.rs b/voxygen/src/render/pipelines/postprocess.rs index 15130f2417..71ff04b601 100644 --- a/voxygen/src/render/pipelines/postprocess.rs +++ b/voxygen/src/render/pipelines/postprocess.rs @@ -1,5 +1,5 @@ use super::super::{AaMode, GlobalsLayouts, Mesh, Tri}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] @@ -23,7 +23,7 @@ impl Locals { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pub pos: [f32; 2], } diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index 3af3760840..cd2be9f80a 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -2,11 +2,11 @@ use super::super::{ AaMode, ColLightInfo, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout, TerrainVertex, Texture, }; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { shadow_matrices: [[f32; 4]; 4], texture_mats: [[f32; 4]; 4], @@ -80,12 +80,23 @@ pub fn create_col_lights( ..Default::default() }; + let view_info = wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }; + renderer.create_texture_with_data_raw( &texture_info, + &view_info, &sampler_info, col_lights_size.x * 4, - [col_lights_size.x, col_lights_size.y], - col_lights.as_bytes(), + bytemuck::cast_slice(&col_lights), ) } diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 342e2a4fad..712de2619a 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -1,8 +1,8 @@ use super::super::{AaMode, GlobalsLayouts, Mesh, Quad}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pub pos: [f32; 3], } diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index fdfeb01d7e..c7ad1582e8 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -1,10 +1,10 @@ use super::super::{AaMode, GlobalsLayouts, TerrainLayout}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use core::fmt; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos: [f32; 3], // Because we try to restrict terrain sprite data to a 128×128 block @@ -70,7 +70,7 @@ impl Vertex { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Instance { pos_ori: u32, inst_mat0: [f32; 4], @@ -122,7 +122,7 @@ impl Default for Instance { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { // Each matrix performs rotatation, translation, and scaling, relative to the sprite // origin, for all sprite instances. The matrix will be in an array indexed by the diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 13957a75a1..7a397aef4a 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -1,9 +1,9 @@ use super::super::{AaMode, GlobalsLayouts}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos_norm: u32, atlas_pos: u32, @@ -118,7 +118,7 @@ impl Vertex { self.pos_norm = (self.pos_norm & !(0xF << 27)) | ((bone_idx as u32 & 0xF) << 27); } - fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> { + pub fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> { use std::mem; wgpu::VertexBufferDescriptor { stride: mem::size_of::() as wgpu::BufferAddress, @@ -129,7 +129,7 @@ impl Vertex { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { model_offs: [f32; 3], load_time: f32, diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs index 4be2660cff..e8f5b73458 100644 --- a/voxygen/src/render/pipelines/ui.rs +++ b/voxygen/src/render/pipelines/ui.rs @@ -1,9 +1,9 @@ use super::super::{AaMode, GlobalsLayouts, Quad, Tri}; -use bytemuck::Pod; +use bytemuck::{Pod, Zeroable}; use vek::*; #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { pos: [f32; 2], uv: [f32; 2], @@ -24,7 +24,7 @@ impl Vertex { } #[repr(C)] -#[derive(Copy, Clone, Debug, Pod)] +#[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { pos: [f32; 4], } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 339fa49e04..6c0bc30424 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -19,7 +19,7 @@ use vek::*; /// A type representing data that can be converted to an immutable texture map /// of ColLight data (used for texture atlases created during greedy meshing). -pub type ColLightInfo = (Vec<[u8; 4]>, Vec2); +pub type ColLightInfo = (Vec<[u8; 4]>, Vec2); /// Load from a GLSL file. pub struct Glsl(String); @@ -150,11 +150,9 @@ impl assets::Compound for Shaders { pub struct ShadowMapRenderer { // directed_encoder: gfx::Encoder, // point_encoder: gfx::Encoder, - directed_depth_stencil_view: wgpu::TextureView, - directed_sampler: wgpu::Sampler, + directed_depth_stencil: Texture, - point_depth_stencil_view: wgpu::TextureView, - point_sampler: wgpu::Sampler, + point_depth_stencil: Texture, point_pipeline: shadow::ShadowPipeline, terrain_directed_pipeline: shadow::ShadowPipeline, @@ -179,7 +177,9 @@ pub struct Layouts { /// rendering subsystem and contains any state necessary to interact with the /// GPU, along with pipeline state objects (PSOs) needed to renderer different /// kinds of models to the screen. -pub struct Renderer { +pub struct Renderer<'a> { + window: &'a winit::window::Window, + device: wgpu::Device, queue: wgpu::Queue, swap_chain: wgpu::SwapChain, @@ -218,13 +218,10 @@ pub struct Renderer { mode: RenderMode, } -impl Renderer { +impl<'a> Renderer<'a> { /// Create a new `Renderer` from a variety of backend-specific components /// and the window targets. - pub async fn new( - window: &winit::window::Window, - mode: RenderMode, - ) -> Result { + pub fn new(window: &'a winit::window::Window, mode: RenderMode) -> Result { // Enable seamless cubemaps globally, where available--they are essentially a // strict improvement on regular cube maps. // @@ -241,29 +238,27 @@ impl Renderer { #[allow(unsafe_code)] let surface = unsafe { instance.create_surface(window) }; - let adapter = instance - .request_adapter(wgpu::RequestAdapterOptionsBase { + let adapter = futures::executor::block_on(instance.request_adapter( + &wgpu::RequestAdapterOptionsBase { power_preference: wgpu::PowerPreference::HighPerformance, - compatible_surface: Some(surface), - }) - .await - .ok_or(RenderError::CouldNotFindAdapter)?; + compatible_surface: Some(&surface), + }, + )) + .ok_or(RenderError::CouldNotFindAdapter)?; use wgpu::{Features, Limits}; - let (device, queue) = adapter - .request_device( - wgpu::DeviceDescriptor { - // TODO - features: Features::DEPTH_CLAMPING | Features::ADDRESS_MODE_CLAMP_TO_BORDER, - limits: Limits::default(), - shader_validation: true, - }, - None, - ) - .await?; + let (device, queue) = futures::executor::block_on(adapter.request_device( + &wgpu::DeviceDescriptor { + // TODO + features: Features::DEPTH_CLAMPING | Features::ADDRESS_MODE_CLAMP_TO_BORDER, + limits: Limits::default(), + shader_validation: true, + }, + None, + ))?; - let info = device.get_info(); + let info = adapter.get_info(); info!( ?info.name, ?info.vendor, @@ -276,8 +271,8 @@ impl Renderer { let sc_desc = wgpu::SwapChainDescriptor { usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, format: wgpu::TextureFormat::Bgra8UnormSrgb, - width: dims.0, - height: dims.1, + width: dims.width, + height: dims.height, present_mode: wgpu::PresentMode::Immediate, }; @@ -285,7 +280,7 @@ impl Renderer { let shadow_views = Self::create_shadow_views( &device, - (dims.0, dims.1), + (dims.width, dims.height), &ShadowMapMode::try_from(mode.shadow).unwrap_or_default(), ) .map_err(|err| { @@ -334,14 +329,10 @@ impl Renderer { point_shadow_pipeline, terrain_directed_shadow_pipeline, figure_directed_shadow_pipeline, - ) = create_pipelines( - &device, - &layouts & mode, - shadow_views.is_some(), - )?; + ) = create_pipelines(&device, &layouts, &mode, &sc_desc, shadow_views.is_some())?; let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) = - Self::create_rt_views(&device, (dims.0, dims.1), &mode)?; + Self::create_rt_views(&device, (dims.width, dims.height), &mode)?; let shadow_map = if let ( Some(point_pipeline), @@ -354,25 +345,16 @@ impl Renderer { figure_directed_shadow_pipeline, shadow_views, ) { - let ( - point_depth_stencil_view, - point_res, - point_sampler, - directed_depth_stencil_view, - directed_res, - directed_sampler, - ) = shadow_views; + let (point_depth_stencil, directed_depth_stencil) = shadow_views; let layout = shadow::ShadowLayout::new(&device); Some(ShadowMapRenderer { - directed_depth_stencil_view, - directed_sampler, + directed_depth_stencil, // point_encoder: factory.create_command_buffer().into(), // directed_encoder: factory.create_command_buffer().into(), - point_depth_stencil_view, - point_sampler, + point_depth_stencil, point_pipeline, terrain_directed_pipeline, @@ -405,6 +387,8 @@ impl Renderer { )?; Ok(Self { + window, + device, queue, swap_chain, @@ -472,43 +456,24 @@ impl Renderer { /// Resize internal render targets to match window render target dimensions. pub fn on_resize(&mut self) -> Result<(), RenderError> { - let dims = self.win_color_view.get_dimensions(); + let dims = self.window.inner_size(); // Avoid panics when creating texture with w,h of 0,0. - if dims.0 != 0 && dims.1 != 0 { - let ( - tgt_color_view, - tgt_depth_stencil_view, - tgt_color_pp_view, - tgt_color_res, - tgt_depth_res, - tgt_color_res_pp, - ) = Self::create_rt_views(&mut self.factory, (dims.0, dims.1), &self.mode)?; - self.tgt_color_res = tgt_color_res; - self.tgt_depth_res = tgt_depth_res; - self.tgt_color_res_pp = tgt_color_res_pp; + if dims.width != 0 && dims.height != 0 { + let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) = + Self::create_rt_views(&mut self.device, (dims.width, dims.height), &self.mode)?; + self.win_depth_view = win_depth_view; self.tgt_color_view = tgt_color_view; self.tgt_depth_stencil_view = tgt_depth_stencil_view; self.tgt_color_pp_view = tgt_color_pp_view; if let (Some(shadow_map), ShadowMode::Map(mode)) = (self.shadow_map.as_mut(), self.mode.shadow) { - match Self::create_shadow_views(&mut self.factory, (dims.0, dims.1), &mode) { - Ok(( - point_depth_stencil_view, - point_res, - point_sampler, - directed_depth_stencil_view, - directed_res, - directed_sampler, - )) => { - shadow_map.point_depth_stencil_view = point_depth_stencil_view; - shadow_map.point_res = point_res; - shadow_map.point_sampler = point_sampler; - - shadow_map.directed_depth_stencil_view = directed_depth_stencil_view; - shadow_map.directed_res = directed_res; - shadow_map.directed_sampler = directed_sampler; + match Self::create_shadow_views(&mut self.device, (dims.width, dims.height), &mode) + { + Ok((point_depth_stencil, directed_depth_stencil)) => { + shadow_map.point_depth_stencil = point_depth_stencil; + shadow_map.directed_depth_stencil = directed_depth_stencil; }, Err(err) => { warn!("Could not create shadow map views: {:?}", err); @@ -522,7 +487,7 @@ impl Renderer { fn create_rt_views( device: &wgpu::Device, - size: (u16, u16), + size: (u32, u32), mode: &RenderMode, ) -> Result< ( @@ -565,9 +530,10 @@ impl Renderer { label: None, format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), dimension: Some(wgpu::TextureViewDimension::D2), - aspect: wgpu::TextureAspect::Color, + // TODO: why is this not Color? + aspect: wgpu::TextureAspect::All, base_mip_level: 0, - level_count: Some(levels), + level_count: None, base_array_layer: 0, array_layer_count: None, }) @@ -596,7 +562,7 @@ impl Renderer { dimension: Some(wgpu::TextureViewDimension::D2), aspect: wgpu::TextureAspect::DepthOnly, base_mip_level: 0, - level_count: Some(levels), + level_count: None, base_array_layer: 0, array_layer_count: None, }); @@ -620,7 +586,7 @@ impl Renderer { dimension: Some(wgpu::TextureViewDimension::D2), aspect: wgpu::TextureAspect::DepthOnly, base_mip_level: 0, - level_count: Some(levels), + level_count: None, base_array_layer: 0, array_layer_count: None, }); @@ -639,28 +605,20 @@ impl Renderer { #[allow(clippy::type_complexity)] fn create_shadow_views( device: &wgpu::Device, - size: (u16, u16), + size: (u32, u32), mode: &ShadowMapMode, - ) -> Result< - ( - wgpu::TextureView, - wgpu::Sampler, - wgpu::TextureView, - wgpu::Sampler, - ), - RenderError, - > { + ) -> Result<(Texture, Texture), RenderError> { // (Attempt to) apply resolution factor to shadow map resolution. let resolution_factor = mode.resolution.clamped(0.25, 4.0); let max_texture_size = Self::max_texture_size_raw(device); // Limit to max texture size, rather than erroring. let size = Vec2::new(size.0, size.1).map(|e| { - let size = f32::from(e) * resolution_factor; + let size = e as f32 * resolution_factor; // NOTE: We know 0 <= e since we clamped the resolution factor to be between // 0.25 and 4.0. - if size <= f32::from(max_texture_size) { - size as u16 + if size <= max_texture_size as f32 { + size as u32 } else { max_texture_size } @@ -669,7 +627,7 @@ impl Renderer { let levels = 1; // Limit to max texture size rather than erroring. let two_size = size.map(|e| { - u16::checked_next_power_of_two(e) + u32::checked_next_power_of_two(e) .filter(|&e| e <= max_texture_size) .unwrap_or(max_texture_size) }); @@ -688,17 +646,17 @@ impl Renderer { // diag_size would be 0 too). And it must be <= diag_size, // since min_size <= max_size. Therefore, if diag_size fits in a // u16, so does diag_cross_size. - (diag_size as u16, diag_cross_size as u16) + (diag_size as u32, diag_cross_size as u32) } else { // Limit to max texture resolution rather than error. - (max_texture_size as u16, max_texture_size as u16) + (max_texture_size as u32, max_texture_size as u32) }; - let diag_two_size = u16::checked_next_power_of_two(diag_size) + let diag_two_size = u32::checked_next_power_of_two(diag_size) .filter(|&e| e <= max_texture_size) // Limit to max texture resolution rather than error. .unwrap_or(max_texture_size); - let point_shadow_tex = device.create_texture(&wgpu::TextureDescriptor { + let point_shadow_tex = wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { width: diag_two_size / 4, @@ -710,20 +668,9 @@ impl Renderer { dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Depth24Plus, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }); + }; - let point_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor { - label: None, - format: Some(wgpu::TextureFormat::Depth24Plus), - dimension: Some(wgpu::TextureViewDimension::Cube), - aspect: wgpu::TextureAspect::DepthOnly, - base_mip_level: 0, - level_count: Some(levels), - base_array_layer: 0, - array_layer_count: None, - }); - - let directed_shadow_tex = device.create_texture(&wgpu::TextureDescriptor { + let directed_shadow_tex = wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { width: diag_two_size, @@ -735,18 +682,18 @@ impl Renderer { dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Depth24Plus, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }); + }; - let directed_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor { + let mut view_info = wgpu::TextureViewDescriptor { label: None, format: Some(wgpu::TextureFormat::Depth24Plus), dimension: Some(wgpu::TextureViewDimension::D2), aspect: wgpu::TextureAspect::DepthOnly, base_mip_level: 0, - level_count: Some(levels), + level_count: None, base_array_layer: 0, array_layer_count: None, - }); + }; let sampler_info = wgpu::SamplerDescriptor { label: None, @@ -760,57 +707,52 @@ impl Renderer { ..Default::default() }; - let point_shadow_tex_sampler = device.create_sampler(&sampler_info); - let directed_shadow_tex_sampler = device.create_sampler(&sampler_info); + let point_tgt_shadow = + Texture::new_raw(device, &point_shadow_tex, &view_info, &sampler_info); + view_info.dimension = Some(wgpu::TextureViewDimension::Cube); + let directed_shadow_tex = + Texture::new_raw(device, &directed_shadow_tex, &view_info, &sampler_info); - Ok(( - point_tgt_shadow_view, - point_shadow_tex_sampler, - directed_tgt_shadow_view, - directed_shadow_tex_sampler, - )) + Ok((point_tgt_shadow, directed_shadow_tex)) } /// Get the resolution of the render target. - /// Note: the change after a resize can be delayed so - /// don't rely on this value being constant between resize events - pub fn get_resolution(&self) -> Vec2 { - Vec2::new( - self.win_color_view.get_dimensions().0, - self.win_color_view.get_dimensions().1, - ) + pub fn get_resolution(&self) -> Vec2 { + let dims = self.window.inner_size(); + + Vec2::new(dims.width, dims.height) } /// Get the resolution of the shadow render target. - pub fn get_shadow_resolution(&self) -> (Vec2, Vec2) { + pub fn get_shadow_resolution(&self) -> (Vec2, Vec2) { if let Some(shadow_map) = &self.shadow_map { - let point_dims = shadow_map.point_depth_stencil_view.get_dimensions(); - let directed_dims = shadow_map.directed_depth_stencil_view.get_dimensions(); + let point_dims = shadow_map.point_depth_stencil.get_dimensions(); + let directed_dims = shadow_map.directed_depth_stencil.get_dimensions(); ( - Vec2::new(point_dims.0, point_dims.1), - Vec2::new(directed_dims.0, directed_dims.1), + Vec2::new(point_dims.width, point_dims.height), + Vec2::new(directed_dims.width, directed_dims.height), ) } else { (Vec2::new(1, 1), Vec2::new(1, 1)) } } - /// Queue the clearing of the shadow targets ready for a new frame to be - /// rendered. - pub fn clear_shadows(&mut self) { - span!(_guard, "clear_shadows", "Renderer::clear_shadows"); - if !self.mode.shadow.is_map() { - return; - } - if let Some(shadow_map) = self.shadow_map.as_mut() { - // let point_encoder = &mut shadow_map.point_encoder; - let point_encoder = &mut self.encoder; - point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0); - // let directed_encoder = &mut shadow_map.directed_encoder; - let directed_encoder = &mut self.encoder; - directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view, 1.0); - } - } + // /// Queue the clearing of the shadow targets ready for a new frame to be + // /// rendered. + // pub fn clear_shadows(&mut self) { + // span!(_guard, "clear_shadows", "Renderer::clear_shadows"); + // if !self.mode.shadow.is_map() { + // return; + // } + // if let Some(shadow_map) = self.shadow_map.as_mut() { + // // let point_encoder = &mut shadow_map.point_encoder; + // let point_encoder = &mut self.encoder; + // point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0); + // // let directed_encoder = &mut shadow_map.directed_encoder; + // let directed_encoder = &mut self.encoder; + // directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view, + // 1.0); } + // } /// NOTE: Supported by Vulkan (by default), DirectX 10+ (it seems--it's hard /// to find proof of this, but Direct3D 10 apparently does it by @@ -839,15 +781,6 @@ impl Renderer { // } } - /// Queue the clearing of the depth target ready for a new frame to be - /// rendered. - pub fn clear(&mut self) { - span!(_guard, "clear", "Renderer::clear"); - self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0); - // self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0); - self.encoder.clear_depth(&self.win_depth_view, 1.0); - } - // /// Set up shadow rendering. // pub fn start_shadows(&mut self) { // if !self.mode.shadow.is_map() { @@ -879,8 +812,7 @@ impl Renderer { /// items. pub fn flush(&mut self) { span!(_guard, "flush", "Renderer::flush"); - self.encoder.flush(&mut self.device); - self.device.cleanup(); + self.device.poll(wgpu::Maintain::Poll); // If the shaders files were changed attempt to recreate the shaders if self.shaders.reloaded() { @@ -891,9 +823,11 @@ impl Renderer { /// Recreate the pipelines fn recreate_pipelines(&mut self) { match create_pipelines( - &mut self.factory, + &self.device, + &self.layouts, &self.shaders.read(), &self.mode, + &self.sc_desc, self.shadow_map.is_some(), ) { Ok(( @@ -907,7 +841,7 @@ impl Renderer { lod_terrain_pipeline, clouds_pipeline, postprocess_pipeline, - player_shadow_pipeline, + //player_shadow_pipeline, point_shadow_pipeline, terrain_directed_shadow_pipeline, figure_directed_shadow_pipeline, @@ -922,7 +856,7 @@ impl Renderer { self.lod_terrain_pipeline = lod_terrain_pipeline; self.clouds_pipeline = clouds_pipeline; self.postprocess_pipeline = postprocess_pipeline; - self.player_shadow_pipeline = player_shadow_pipeline; + //self.player_shadow_pipeline = player_shadow_pipeline; if let ( Some(point_pipeline), Some(terrain_directed_pipeline), @@ -948,14 +882,14 @@ impl Renderer { &mut self, vals: &[T], ) -> Result, RenderError> { - let mut consts = Consts::new(&mut self.factory, vals.len()); - consts.update(&mut self.encoder, vals, 0)?; + let mut consts = Consts::new(&self.device, vals.len() as u64); + consts.update(&self.device, &self.queue, vals, 0); Ok(consts) } /// Update a set of constants with the provided values. pub fn update_consts(&mut self, consts: &mut Consts, vals: &[T]) { - consts.update(&mut self.encoder, vals, 0) + consts.update(&self.device, &self.queue, vals, 0) } /// Create a new set of instances with the provided values. @@ -963,39 +897,31 @@ impl Renderer { &mut self, vals: &[T], ) -> Result, RenderError> { - let mut instances = Instances::new(&mut self.factory, vals.len())?; - instances.update(&mut self.encoder, vals)?; + let mut instances = Instances::new(&self.device, vals.len() as u64); + instances.update(&self.device, &self.queue, vals, 0); Ok(instances) } /// Create a new model from the provided mesh. pub fn create_model(&mut self, mesh: &Mesh) -> Result, RenderError> { - Ok(Model::new(&mut self.factory, mesh)) + Ok(Model::new(&self.device, mesh)) } /// Create a new dynamic model with the specified size. - pub fn create_dynamic_model( - &mut self, - size: usize, - ) -> Result, RenderError> { - Model::new(&self.device, size) + pub fn create_dynamic_model(&mut self, size: u64) -> Model { + Model::new_dynamic(&self.device, size) } /// Update a dynamic model with a mesh and a offset. - pub fn update_model( - &mut self, - model: &Model, - mesh: &Mesh, - offset: usize, - ) -> Result<(), RenderError> { - model.update(&mut self.encoder, mesh, offset) + pub fn update_model(&mut self, model: &Model, mesh: &Mesh, offset: u64) { + model.update(&self.device, &self.queue, mesh, offset) } /// Return the maximum supported texture size. - pub fn max_texture_size(&self) -> u16 { Self::max_texture_size_raw(&self.factory) } + pub fn max_texture_size(&self) -> u32 { Self::max_texture_size_raw(&self.device) } /// Return the maximum supported texture size from the factory. - fn max_texture_size_raw(device: &wgpu::Device) -> u16 { + fn max_texture_size_raw(_device: &wgpu::Device) -> u32 { // This value is temporary as there are plans to include a way to get this in // wgpu this is just a sane standard for now 8192 @@ -1004,18 +930,19 @@ impl Renderer { /// Create a new immutable texture from the provided image. pub fn create_texture_with_data_raw( &mut self, - texture_info: wgpu::TextureDescriptor, - sampler_info: wgpu::SamplerDescriptor, + texture_info: &wgpu::TextureDescriptor, + view_info: &wgpu::TextureViewDescriptor, + sampler_info: &wgpu::SamplerDescriptor, bytes_per_row: u32, data: &[u8], ) -> Texture { - let tex = Texture::new_raw(&self.device, texture_info, sampler_info); + let tex = Texture::new_raw(&self.device, &texture_info, &view_info, &sampler_info); tex.update( &self.device, &self.queue, [0; 2], - [texture_info.size.x, texture_info.size.y], + [texture_info.size.width, texture_info.size.height], data, bytes_per_row, ); @@ -1026,10 +953,11 @@ impl Renderer { /// Create a new raw texture. pub fn create_texture_raw( &mut self, - texture_info: wgpu::TextureDescriptor, - sampler_info: wgpu::SamplerDescriptor, + texture_info: &wgpu::TextureDescriptor, + view_info: &wgpu::TextureViewDescriptor, + sampler_info: &wgpu::SamplerDescriptor, ) -> Texture { - Texture::new_raw(&self.device, texture_info, sampler_info) + Texture::new_raw(&self.device, texture_info, view_info, sampler_info) } /// Create a new texture from the provided image. @@ -1040,7 +968,7 @@ impl Renderer { image: &image::DynamicImage, filter_method: Option, address_mode: Option, - ) -> Texture { + ) -> Result { Texture::new( &self.device, &self.queue, @@ -1054,8 +982,8 @@ impl Renderer { /// specified dimensions. /// /// Currently only supports Rgba8Srgb - pub fn create_dynamic_texture(&mut self, dims: Vec2) -> Texture { - Texture::new_dynamic(&mut self.factory, dims.x, dims.y) + pub fn create_dynamic_texture(&mut self, dims: Vec2) -> Texture { + Texture::new_dynamic(&self.device, dims.x, dims.y) } /// Update a texture with the provided offset, size, and data. @@ -1064,8 +992,8 @@ impl Renderer { pub fn update_texture( &mut self, texture: &Texture, /* */ - offset: [u16; 2], - size: [u16; 2], + offset: [u32; 2], + size: [u32; 2], // TODO // data: &[<::Surface as // gfx::format::SurfaceTyped>::DataType], ) -> Result<(), RenderError> @@ -1078,7 +1006,14 @@ impl Renderer { data: &[[u8; 4]], bytes_per_row: u32, ) { - texture.update(&mut self.encoder, offset, size, data, bytes_per_row) + texture.update( + &self.device, + &self.queue, + offset, + size, + bytemuck::cast_slice(data), + bytes_per_row, + ) } /// Creates a download buffer, downloads the win_color_view, and converts to @@ -1945,18 +1880,18 @@ fn create_pipelines( options.set_optimization_level(OptimizationLevel::Performance); options.set_include_callback(move |name, _, shader_name, _| { Ok(ResolvedInclude { - resolved_name: name, + resolved_name: name.to_string(), content: match name { "constants.glsl" => constants, - "globals.glsl" => globals, - "shadows.glsl" => shadows, - "sky.glsl" => sky, - "light.glsl" => light, - "srgb.glsl" => srgb, - "random.glsl" => &random, - "lod.glsl" => &lod, - "anti-aliasing.glsl" => &anti_alias, - "cloud.glsl" => &cloud, + "globals.glsl" => *globals, + "shadows.glsl" => *shadows, + "sky.glsl" => *sky, + "light.glsl" => *light, + "srgb.glsl" => *srgb, + "random.glsl" => *random, + "lod.glsl" => *lod, + "anti-aliasing.glsl" => *anti_alias, + "cloud.glsl" => *cloud, other => return Err(format!("Include {} is not defined", other)), }, }) @@ -1975,7 +1910,7 @@ fn create_pipelines( let figure_vert_mod = create_shader_module( device, &mut compiler, - figure_vert, + &figure_vert, ShaderKind::Vertex, "figure-vert.glsl", &options, @@ -1984,7 +1919,7 @@ fn create_pipelines( let terrain_point_shadow_vert_mod = create_shader_module( device, &mut compiler, - terrain_point_shadow_vert, + &terrain_point_shadow_vert, ShaderKind::Vertex, "light-shadows-vert.glsl", &options, @@ -1993,7 +1928,7 @@ fn create_pipelines( let terrain_directed_shadow_vert_mod = create_shader_module( device, &mut compiler, - terrain_directed_shadow_vert, + &terrain_directed_shadow_vert, ShaderKind::Vertex, "light-shadows-directed-vert.glsl", &options, @@ -2002,7 +1937,7 @@ fn create_pipelines( let figure_directed_shadow_vert_mod = create_shader_module( device, &mut compiler, - figure_directed_shadow_vert, + &figure_directed_shadow_vert, ShaderKind::Vertex, "light-shadows-figure-vert.glsl", &options, @@ -2022,24 +1957,24 @@ fn create_pipelines( // Construct a pipeline for rendering skyboxes let skybox_pipeline = skybox::SkyboxPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.skybox_vert.read().0, ShaderKind::Vertex, "skybox-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.skybox_frag.read().0, ShaderKind::Fragment, "skybox-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, mode.aa, ); @@ -2047,55 +1982,57 @@ fn create_pipelines( let figure_pipeline = figure::FigurePipeline::new( device, &figure_vert_mod, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.figure_frag.read().0, ShaderKind::Fragment, "figure-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.figure, mode.aa, ); // Construct a pipeline for rendering terrain let terrain_pipeline = terrain::TerrainPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.terrain_vert.read().0, ShaderKind::Vertex, "terrain-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.terrain_frag.read().0, ShaderKind::Fragment, "terrain-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.terrain, mode.aa, ); // Construct a pipeline for rendering fluids let fluid_pipeline = fluid::FluidPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.fluid_vert.read().0, ShaderKind::Vertex, "terrain-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, match mode.fluid { @@ -2105,105 +2042,109 @@ fn create_pipelines( ShaderKind::Fragment, "fluid-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.fluid, mode.aa, ); // Construct a pipeline for rendering sprites let sprite_pipeline = sprite::SpritePipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.sprite_vert.read().0, ShaderKind::Vertex, "sprite-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.sprite_frag.read().0, ShaderKind::Fragment, "sprite-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.sprite, + &layouts.terrain, mode.aa, ); // Construct a pipeline for rendering particles let particle_pipeline = particle::ParticlePipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.particle_vert.read().0, ShaderKind::Vertex, "particle-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.particle_frag.read().0, ShaderKind::Fragment, "particle-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, mode.aa, ); // Construct a pipeline for rendering UI elements let ui_pipeline = ui::UIPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.ui_vert.read().0, ShaderKind::Vertex, "ui-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.ui_frag.read().0, ShaderKind::Fragment, "ui-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.ui, mode.aa, ); // Construct a pipeline for rendering terrain let lod_terrain_pipeline = lod_terrain::LodTerrainPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.lod_terrain_vert.read().0, ShaderKind::Vertex, "lod-terrain-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.lod_terrain_frag.read().0, ShaderKind::Fragment, "lod-terrain-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, mode.aa, ); @@ -2221,24 +2162,25 @@ fn create_pipelines( // Construct a pipeline for rendering our post-processing let postprocess_pipeline = postprocess::PostProcessPipeline::new( device, - create_shader_module( + &create_shader_module( device, &mut compiler, shaders.postprocess_vert.read().0, ShaderKind::Vertex, "postprocess-vert.glsl", &options, - ), - create_shader_module( + )?, + &create_shader_module( device, &mut compiler, shaders.postprocess_frag.read().0, ShaderKind::Fragment, "postprocess-frag.glsl", &options, - ), + )?, sc_desc, - layouts, + &layouts.global, + &layouts.postprocess, mode.aa, ); @@ -2368,5 +2310,9 @@ pub fn create_shader_module( let spv = compiler.compile_into_spirv(source, kind, file_name, "main", Some(options))?; - Ok(device.create_shader_module(wgpu::ShaderModule::SpirV(Cow::Bowrrowed(spv.as_binary())))) + Ok( + device.create_shader_module(wgpu::ShaderModuleSource::SpirV(Cow::Borrowed( + spv.as_binary(), + ))), + ) } diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index 8b65baaa41..375015f9ed 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -4,7 +4,8 @@ use wgpu::Extent3d; /// Represents an image that has been uploaded to the GPU. pub struct Texture { - pub tex: wgpu::TextureView, + pub tex: wgpu::Texture, + pub view: wgpu::TextureView, pub sampler: wgpu::Sampler, size: Extent3d, } @@ -49,7 +50,7 @@ impl Texture { mip_level: 0, origin: wgpu::Origin3d::ZERO, }, - &[buffer.as_slice()], + buffer.as_slice(), wgpu::TextureDataLayout { offset: 0, bytes_per_row: image.width() * 4, @@ -73,21 +74,33 @@ impl Texture { ..Default::default() }; + let view = tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }); + Ok(Self { tex, + view, sampler: device.create_sampler(&sampler_info), size, }) } - pub fn new_dynamic(device: &wgpu::Device, width: u16, height: u16) -> Self { + pub fn new_dynamic(device: &wgpu::Device, width: u32, height: u32) -> Self { let size = wgpu::Extent3d { width, height, depth: 1, }; - let tex_info = device.create_texture(&wgpu::TextureDescriptor { + let tex_info = wgpu::TextureDescriptor { label: None, size, mip_level_count: 1, @@ -95,7 +108,7 @@ impl Texture { dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED, - }); + }; let sampler_info = wgpu::SamplerDescriptor { label: None, @@ -108,19 +121,35 @@ impl Texture { ..Default::default() }; - Self::new_raw(device, tex_info, sampler_info) + let view_info = wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }; + + Self::new_raw(device, &tex_info, &view_info, &sampler_info) } pub fn new_raw( device: &wgpu::Device, - texture_info: wgpu::TextureDescriptor, - sampler_info: wgpu::SamplerDescriptor, + texture_info: &wgpu::TextureDescriptor, + view_info: &wgpu::TextureViewDescriptor, + sampler_info: &wgpu::SamplerDescriptor, ) -> Self { - Ok(Self { - tex: device.create_texture(&texture_info), - sampler: device.create_sampler(&sampler_info), + let tex = device.create_texture(texture_info); + let view = tex.create_view(view_info); + + Self { + tex, + view, + sampler: device.create_sampler(sampler_info), size: texture_info.size, - }) + } } /// Update a texture with the given data (used for updating the glyph cache @@ -129,11 +158,11 @@ impl Texture { &self, device: &wgpu::Device, queue: &wgpu::Queue, - offset: [u16; 2], - size: [u16; 2], + offset: [u32; 2], + size: [u32; 2], data: &[u8], bytes_per_row: u32, - ) -> Result<(), RenderError> { + ) { // TODO: Only works for 2D images queue.write_texture( wgpu::TextureCopyViewBase { @@ -146,12 +175,10 @@ impl Texture { }, }, data, - // TODO: I heard some rumors that there are other - // formats that are not Rgba8 wgpu::TextureDataLayout { offset: 0, bytes_per_row, - rows_per_image: self.size.y, + rows_per_image: self.size.height, }, wgpu::Extent3d { width: size[0], diff --git a/voxygen/src/run.rs b/voxygen/src/run.rs index b17e2ad236..03460cff3b 100644 --- a/voxygen/src/run.rs +++ b/voxygen/src/run.rs @@ -168,19 +168,19 @@ fn handle_main_events_cleared( if let Some(last) = states.last_mut() { span!(guard, "Render"); let renderer = global_state.window.renderer_mut(); - // Clear the shadow maps. - renderer.clear_shadows(); - // Clear the screen - renderer.clear(); + // // Clear the shadow maps. + // renderer.clear_shadows(); + // // Clear the screen + // renderer.clear(); // Render the screen using the global renderer last.render(renderer, &global_state.settings); // Finish the frame. - global_state.window.renderer_mut().flush(); - // Display the frame on the window. - global_state - .window - .swap_buffers() - .expect("Failed to swap window buffers!"); + // global_state.window.renderer_mut().flush(); + // // Display the frame on the window. + // global_state + // .window + // .swap_buffers() + // .expect("Failed to swap window buffers!"); drop(guard); } diff --git a/voxygen/src/scene/figure/cache.rs b/voxygen/src/scene/figure/cache.rs index c5ea7f98c4..5b8afb9aa2 100644 --- a/voxygen/src/scene/figure/cache.rs +++ b/voxygen/src/scene/figure/cache.rs @@ -1,6 +1,6 @@ use super::{load::BodySpec, FigureModelEntry}; use crate::{ - mesh::{greedy::GreedyMesh, Meshable}, + mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain}, render::{BoneMeshes, ColLightInfo, FigureModel, Mesh, Renderer, TerrainVertex}, scene::camera::CameraMode, }; @@ -476,11 +476,10 @@ where offset: Vec3, bone_idx: u8, ) -> BoneMeshes { - let (opaque, _, _, bounds) = - Meshable::::generate_mesh( - segment, - (greedy, opaque_mesh, offset, Vec3::one(), bone_idx), - ); + let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain( + segment, + (greedy, opaque_mesh, offset, Vec3::one(), bone_idx), + ); (opaque, bounds) } @@ -492,17 +491,16 @@ where bone_idx: u8, ) -> BoneMeshes { let lod_scale = 0.6; - let (opaque, _, _, bounds) = - Meshable::::generate_mesh( - segment.scaled_by(Vec3::broadcast(lod_scale)), - ( - greedy, - opaque_mesh, - offset * lod_scale, - Vec3::one() / lod_scale, - bone_idx, - ), - ); + let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain( + segment.scaled_by(Vec3::broadcast(lod_scale)), + ( + greedy, + opaque_mesh, + offset * lod_scale, + Vec3::one() / lod_scale, + bone_idx, + ), + ); (opaque, bounds) } @@ -514,17 +512,16 @@ where bone_idx: u8, ) -> BoneMeshes { let lod_scale = 0.3; - let (opaque, _, _, bounds) = - Meshable::::generate_mesh( - segment.scaled_by(Vec3::broadcast(lod_scale)), - ( - greedy, - opaque_mesh, - offset * lod_scale, - Vec3::one() / lod_scale, - bone_idx, - ), - ); + let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain( + segment.scaled_by(Vec3::broadcast(lod_scale)), + ( + greedy, + opaque_mesh, + offset * lod_scale, + Vec3::one() / lod_scale, + bone_idx, + ), + ); (opaque, bounds) } diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 912bfb2bae..c36f9da229 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -5230,12 +5230,9 @@ impl FigureColLights { span!(_guard, "create_figure", "FigureColLights::create_figure"); let atlas = &mut self.atlas; let allocation = atlas - .allocate(guillotiere::Size::new( - i32::from(tex_size.x), - i32::from(tex_size.y), - )) + .allocate(guillotiere::Size::new(tex_size.x as i32, tex_size.y as i32)) .expect("Not yet implemented: allocate new atlas on allocation failure."); - let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size))?; + let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size)); let model_len = u32::try_from(opaque.vertices().len()) .expect("The model size for this figure does not fit in a u32!"); let model = renderer.create_model(&opaque)?; @@ -5262,8 +5259,7 @@ impl FigureColLights { #[allow(clippy::unnecessary_wraps)] fn make_atlas(renderer: &mut Renderer) -> Result { let max_texture_size = renderer.max_texture_size(); - let atlas_size = - guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size)); + let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32); let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions { // TODO: Verify some good empirical constants. small_size_threshold: 32, @@ -5286,7 +5282,7 @@ impl FigureColLights { (0, 0), gfx::format::Swizzle::new(), gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, + gfx::texture::FilterMetho>:Bilinear, gfx::texture::WrapMode::Clamp, ), )?; @@ -5467,18 +5463,16 @@ impl FigureState { self.last_light, self.last_glow, ); - renderer.update_consts(&mut self.locals, &[locals]).unwrap(); + renderer.update_consts(&mut self.locals, &[locals]); let lantern_offset = anim::compute_matrices(&self.skeleton, mat, buf); let new_bone_consts = figure_bone_data_from_anim(buf); - renderer - .update_consts( - &mut self.meta.bone_consts, - &new_bone_consts[0..S::BONE_COUNT], - ) - .unwrap(); + renderer.update_consts( + &mut self.meta.bone_consts, + &new_bone_consts[0..S::BONE_COUNT], + ); self.lantern_offset = lantern_offset; let smoothing = (5.0 * dt).min(1.0); diff --git a/voxygen/src/scene/lod.rs b/voxygen/src/scene/lod.rs index 926559f199..ab190e340d 100644 --- a/voxygen/src/scene/lod.rs +++ b/voxygen/src/scene/lod.rs @@ -26,7 +26,7 @@ impl Lod { model: None, data: LodData::new( renderer, - client.world_data().chunk_size(), + client.world_data().chunk_size().as_(), client.world_data().lod_base.raw(), client.world_data().lod_alt.raw(), client.world_data().lod_horizon.raw(), diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 6f496f5386..9aad8e2216 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -584,9 +584,7 @@ impl Scene { ); lights.sort_by_key(|light| light.get_pos().distance_squared(player_pos) as i32); lights.truncate(MAX_LIGHT_COUNT); - renderer - .update_consts(&mut self.data.lights, &lights) - .expect("Failed to update light constants"); + renderer.update_consts(&mut self.data.lights, &lights); // Update event lights let dt = ecs.fetch::().0; @@ -623,9 +621,7 @@ impl Scene { .collect::>(); shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(player_pos) as i32); shadows.truncate(MAX_SHADOW_COUNT); - renderer - .update_consts(&mut self.data.shadows, &shadows) - .expect("Failed to update light constants"); + renderer.update_consts(&mut self.data.shadows, &shadows); // Remember to put the new loaded distance back in the scene. self.loaded_distance = loaded_distance; @@ -636,48 +632,42 @@ impl Scene { let focus_off = focus_pos.map(|e| e.trunc()); // Update global constants. - renderer - .update_consts(&mut self.data.globals, &[Globals::new( - view_mat, - proj_mat, - cam_pos, - focus_pos, - self.loaded_distance, - self.lod.get_data().tgt_detail as f32, - self.map_bounds, - time_of_day, - scene_data.state.get_time(), - renderer.get_resolution(), - Vec2::new(SHADOW_NEAR, SHADOW_FAR), - lights.len(), - shadows.len(), - NUM_DIRECTED_LIGHTS, - scene_data - .state - .terrain() - .get((cam_pos + focus_off).map(|e| e.floor() as i32)) - .map(|b| b.kind()) - .unwrap_or(BlockKind::Air), - self.select_pos.map(|e| e - focus_off.map(|e| e as i32)), - scene_data.gamma, - scene_data.exposure, - scene_data.ambiance, - self.camera.get_mode(), - scene_data.sprite_render_distance as f32 - 20.0, - )]) - .expect("Failed to update global constants"); - renderer - .update_consts(&mut self.clouds.locals, &[CloudsLocals::new( - proj_mat_inv, - view_mat_inv, - )]) - .expect("Failed to update cloud locals"); - renderer - .update_consts(&mut self.postprocess.locals, &[PostProcessLocals::new( - proj_mat_inv, - view_mat_inv, - )]) - .expect("Failed to update post-process locals"); + renderer.update_consts(&mut self.data.globals, &[Globals::new( + view_mat, + proj_mat, + cam_pos, + focus_pos, + self.loaded_distance, + self.lod.get_data().tgt_detail as f32, + self.map_bounds, + time_of_day, + scene_data.state.get_time(), + renderer.get_resolution().as_(), + Vec2::new(SHADOW_NEAR, SHADOW_FAR), + lights.len(), + shadows.len(), + NUM_DIRECTED_LIGHTS, + scene_data + .state + .terrain() + .get((cam_pos + focus_off).map(|e| e.floor() as i32)) + .map(|b| b.kind()) + .unwrap_or(BlockKind::Air), + self.select_pos.map(|e| e - focus_off.map(|e| e as i32)), + scene_data.gamma, + scene_data.exposure, + scene_data.ambiance, + self.camera.get_mode(), + scene_data.sprite_render_distance as f32 - 20.0, + )]); + renderer.update_consts(&mut self.clouds.locals, &[CloudsLocals::new( + proj_mat_inv, + view_mat_inv, + )]); + renderer.update_consts(&mut self.postprocess.locals, &[PostProcessLocals::new( + proj_mat_inv, + view_mat_inv, + )]); // Maintain LoD. self.lod.maintain(renderer); @@ -985,9 +975,7 @@ impl Scene { }) })); - renderer - .update_consts(&mut self.data.shadow_mats, &shadow_mats) - .expect("Failed to update light constants"); + renderer.update_consts(&mut self.data.shadow_mats, &shadow_mats); } // Remove unused figures. @@ -1028,10 +1016,10 @@ impl Scene { // would instead have this as an extension. if renderer.render_mode().shadow.is_map() && (is_daylight || !light_data.1.is_empty()) { - if is_daylight { - // Set up shadow mapping. - renderer.start_shadows(); - } + // if is_daylight { + // // Set up shadow mapping. + // renderer.start_shadows(); + // } // Render terrain shadows. self.terrain @@ -1041,10 +1029,10 @@ impl Scene { self.figure_mgr .render_shadows(renderer, state, tick, global, light_data, camera_data); - if is_daylight { - // Flush shadows. - renderer.flush_shadows(); - } + // if is_daylight { + // // Flush shadows. + // renderer.flush_shadows(); + // } } let lod = self.lod.get_data(); diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index a33f88a926..008b215729 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -1,6 +1,6 @@ use super::{terrain::BlocksOfInterest, SceneData, Terrain}; use crate::{ - mesh::{greedy::GreedyMesh, Meshable}, + mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_particle}, render::{ pipelines::particle::ParticleMode, GlobalModel, Instances, Light, LodData, Model, ParticleInstance, ParticleVertex, Renderer, @@ -1220,14 +1220,12 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model::generate_mesh(segment, &mut greedy).0; + let mesh = generate_mesh_base_vol_particle(segment, &mut greedy).0; // Center particle vertices around origin for vert in mesh.vertices_mut() { vert.pos[0] -= segment_size.x as f32 / 2.0; diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index cc367d81a0..2033e035b5 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -1,5 +1,5 @@ use crate::{ - mesh::{greedy::GreedyMesh, Meshable}, + mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals, Consts, FigureModel, GlobalModel, Globals, Light, Mesh, Model, PostProcessLocals, @@ -51,10 +51,7 @@ fn generate_mesh<'a>( bone_idx: u8, ) -> BoneMeshes { let (opaque, _, /* shadow */ _, bounds) = - Meshable::::generate_mesh( - segment, - (greedy, mesh, offset, Vec3::one(), bone_idx), - ); + generate_mesh_base_vol_terrain(segment, (greedy, mesh, offset, Vec3::one(), bone_idx)); (opaque /* , shadow */, bounds) } @@ -152,7 +149,7 @@ impl Scene { &alt_image, &horizon_image, 1, - map_border.into(), + //map_border.into(), ), map_bounds, @@ -271,7 +268,7 @@ impl Scene { const SHADOW_NEAR: f32 = 1.0; const SHADOW_FAR: f32 = 25.0; - if let Err(e) = renderer.update_consts(&mut self.data.globals, &[Globals::new( + renderer.update_consts(&mut self.data.globals, &[Globals::new( view_mat, proj_mat, cam_pos, @@ -281,7 +278,7 @@ impl Scene { self.map_bounds, TIME, scene_data.time, - renderer.get_resolution(), + renderer.get_resolution().as_(), Vec2::new(SHADOW_NEAR, SHADOW_FAR), 0, 0, @@ -293,9 +290,7 @@ impl Scene { scene_data.ambiance, self.camera.get_mode(), 250.0, - )]) { - error!(?e, "Renderer failed to update"); - } + )]); self.figure_model_cache .clean(&mut self.col_lights, scene_data.tick); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 137c807464..9e11577a43 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -2,7 +2,11 @@ mod watcher; pub use self::watcher::{BlocksOfInterest, Interaction}; use crate::{ - mesh::{greedy::GreedyMesh, terrain::SUNLIGHT, Meshable}, + mesh::{ + greedy::GreedyMesh, + segment::generate_mesh_base_vol_sprite, + terrain::{generate_mesh, SUNLIGHT}, + }, render::{ pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, TerrainLocals, @@ -30,7 +34,6 @@ use std::sync::{ atomic::{AtomicU64, Ordering}, Arc, }; -use tracing::warn; use treeculler::{BVol, Frustum, AABB}; use vek::*; @@ -174,17 +177,21 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' ) -> MeshWorkerResponse { span!(_guard, "mesh_worker"); let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk); + let mesh; let (light_map, glow_map) = if let Some((light_map, glow_map)) = &skip_remesh { mesh = None; (&**light_map, &**glow_map) } else { let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) = - volume.generate_mesh(( - range, - Vec2::new(max_texture_size, max_texture_size), - &blocks_of_interest, - )); + generate_mesh( + &volume, + ( + range, + Vec2::new(max_texture_size, max_texture_size), + &blocks_of_interest, + ), + ); mesh = Some(MeshWorkerResponseMesh { // TODO: Take sprite bounds into account somehow? z_bounds: (bounds.min.z, bounds.max.z), @@ -198,6 +205,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' let mesh = mesh.as_ref().unwrap(); (&*mesh.light_map, &*mesh.glow_map) }; + MeshWorkerResponse { pos, // Extract sprite locations from volume @@ -363,8 +371,7 @@ impl SpriteRenderContext { let sprite_config = Arc::::load_expect("voxygen.voxel.sprite_manifest").cloned(); - let max_size = - guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size)); + let max_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32); let mut greedy = GreedyMesh::new(max_size); let mut locals_buffer = [SpriteLocals::default(); 8]; let sprite_config_ = &sprite_config; @@ -400,14 +407,15 @@ impl SpriteRenderContext { ) .unwrap_or(zero); let max_model_size = Vec3::new(31.0, 31.0, 63.0); - let model_scale = max_model_size.map2(model_size, |max_sz: f32, cur_sz| { - let scale = max_sz / max_sz.max(cur_sz as f32); - if scale < 1.0 && (cur_sz as f32 * scale).ceil() > max_sz { - scale - 0.001 - } else { - scale - } - }); + let model_scale = + max_model_size.map2(model_size, |max_sz: f32, cur_sz| { + let scale = max_sz / max_sz.max(cur_sz as f32); + if scale < 1.0 && (cur_sz as f32 * scale).ceil() > max_sz { + scale - 0.001 + } else { + scale + } + }); let sprite_mat: Mat4 = Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE); move |greedy: &mut GreedyMesh| { @@ -421,14 +429,15 @@ impl SpriteRenderContext { Vec3::broadcast(1.0) } else { lod_axes * lod_scale_orig - + lod_axes - .map(|e| if e == 0.0 { 1.0 } else { 0.0 }) + + lod_axes.map(|e| { + if e == 0.0 { 1.0 } else { 0.0 } + }) }; - // Mesh generation exclusively acts using side effects; it - // has no + // Mesh generation exclusively acts using side effects; + // it has no // interesting return value, but updates the mesh. let mut opaque_mesh = Mesh::new(); - Meshable::::generate_mesh( + generate_mesh_base_vol_sprite( Segment::from(&model.read().0).scaled_by(lod_scale), (greedy, &mut opaque_mesh, false), ); @@ -438,8 +447,9 @@ impl SpriteRenderContext { sprite_mat * Mat4::scaling_3d(sprite_scale); locals_buffer.iter_mut().enumerate().for_each( |(ori, locals)| { - let sprite_mat = sprite_mat - .rotated_z(f32::consts::PI * 0.25 * ori as f32); + let sprite_mat = sprite_mat.rotated_z( + f32::consts::PI * 0.25 * ori as f32, + ); *locals = SpriteLocals::new( sprite_mat, sprite_scale, @@ -522,8 +532,7 @@ impl SpriteRenderContext { }) .collect(); let sprite_col_lights = - pipelines::shadow::create_col_lights(renderer, &sprite_col_lights) - .expect("Failed to upload sprite color and light data to the GPU!"); + pipelines::shadow::create_col_lights(renderer, &sprite_col_lights); Self { sprite_config: Arc::clone(&sprite_config), @@ -573,8 +582,7 @@ impl Terrain { ) -> Result<(AtlasAllocator, Texture /* */), RenderError> { span!(_guard, "make_atlas", "Terrain::make_atlas"); let max_texture_size = renderer.max_texture_size(); - let atlas_size = - guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size)); + let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32); let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions { // TODO: Verify some good empirical constants. small_size_threshold: 128, @@ -582,7 +590,7 @@ impl Terrain { ..guillotiere::AllocatorOptions::default() }); let texture = renderer.create_texture_raw( - wgpu::TextureDescriptor { + &wgpu::TextureDescriptor { label: Some("Atlas texture"), size: wgpu::Extent3d { width: max_texture_size, @@ -595,7 +603,17 @@ impl Terrain { format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED, }, - wgpu::SamplerDescriptor { + &wgpu::TextureViewDescriptor { + label: Some("Atlas texture view"), + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D1), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }, + &wgpu::SamplerDescriptor { label: Some("Atlas sampler"), address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, @@ -605,7 +623,7 @@ impl Terrain { mipmap_filter: wgpu::FilterMode::Nearest, ..Default::default() }, - )?; + ); Ok((atlas, texture)) } @@ -955,7 +973,6 @@ impl Terrain { break; } - // Find the area of the terrain we want. Because meshing needs to compute things // like ambient occlusion and edge elision, we also need the borders // of the chunk's neighbours too (hence the `- 1` and `+ 1`). let aabr = Aabr { @@ -1022,7 +1039,7 @@ impl Terrain { skip_remesh, started_tick, volume, - max_texture_size, + max_texture_size as u16, chunk, aabb, &sprite_data, @@ -1080,8 +1097,9 @@ impl Terrain { let col_lights = &mut self.col_lights; let allocation = atlas .allocate(guillotiere::Size::new( - i32::from(tex_size.x), - i32::from(tex_size.y), + tex_size.x as i32, /* TODO: adjust ColLightInfo to avoid the + * cast here? */ + tex_size.y as i32, )) .unwrap_or_else(|| { // Atlas allocation failure: try allocating a new texture and atlas. @@ -1104,25 +1122,25 @@ impl Terrain { atlas .allocate(guillotiere::Size::new( - i32::from(tex_size.x), - i32::from(tex_size.y), + tex_size.x as i32, /* TODO: adjust ColLightInfo to avoid + * the + * cast here? */ + tex_size.y as i32, )) .expect("Chunk data does not fit in a texture of maximum size.") }); // NOTE: Cast is safe since the origin was a u16. let atlas_offs = Vec2::new( - allocation.rectangle.min.x as u16, - allocation.rectangle.min.y as u16, + allocation.rectangle.min.x as u32, + allocation.rectangle.min.y as u32, ); - if let Err(err) = renderer.update_texture( + renderer.update_texture( col_lights, atlas_offs.into_array(), tex_size.into_array(), &tex, - ) { - warn!("Failed to update texture: {:?}", err); - } + ); self.insert_chunk(response.pos, TerrainChunkData { load_time, @@ -1152,8 +1170,8 @@ impl Terrain { ) .into_array(), atlas_offs: Vec4::new( - i32::from(atlas_offs.x), - i32::from(atlas_offs.y), + atlas_offs.x as i32, + atlas_offs.y as i32, 0, 0, ) diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 2c00558bb4..81ff306b4a 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -518,7 +518,7 @@ impl KeyMouse { } pub struct Window { - renderer: Renderer, + renderer: Renderer<'static>, window: winit::window::Window, cursor_grabbed: bool, pub pan_sensitivity: u32, @@ -574,7 +574,7 @@ impl Window { // .map_err(|err| Error::BackendError(Box::new(err)))? // .init_gfx::(); - let window = win_builder.build(&event_loop)?; + let window = win_builder.build(&event_loop).unwrap(); let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?; @@ -658,7 +658,7 @@ impl Window { pub fn renderer(&self) -> &Renderer { &self.renderer } - pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } + pub fn renderer_mut(&mut self) -> &mut Renderer<'static> { &mut self.renderer } pub fn resolve_deduplicated_events(&mut self, settings: &mut Settings) { // Handle screenshots and toggling fullscreen @@ -938,9 +938,9 @@ impl Window { match event { WindowEvent::CloseRequested => self.events.push(Event::Close), WindowEvent::Resized(physical) => { - let (mut color_view, mut depth_view) = self.renderer.win_views_mut(); - self.window.resize(physical); - self.window.update_gfx(&mut color_view, &mut depth_view); + // let (mut color_view, mut depth_view) = self.renderer.win_views_mut(); + // self.window.resize(physical); + // self.window.update_gfx(&mut color_view, &mut depth_view); self.renderer.on_resize().unwrap(); // TODO: update users of this event with the fact that it is now the physical // size @@ -1085,32 +1085,24 @@ impl Window { /// Moves cursor by an offset pub fn offset_cursor(&self, d: Vec2) { if d != Vec2::zero() { - if let Err(err) = - self.window - .window() - .set_cursor_position(winit::dpi::LogicalPosition::new( - d.x as f64 + self.cursor_position.x, - d.y as f64 + self.cursor_position.y, - )) + if let Err(err) = self + .window + .set_cursor_position(winit::dpi::LogicalPosition::new( + d.x as f64 + self.cursor_position.x, + d.y as f64 + self.cursor_position.y, + )) { error!("Error setting cursor position: {:?}", err); } } } - pub fn swap_buffers(&self) -> Result<(), Error> { - span!(_guard, "swap_buffers", "Window::swap_buffers"); - self.window - .swap_buffers() - .map_err(|err| Error::BackendError(Box::new(err))) - } - pub fn is_cursor_grabbed(&self) -> bool { self.cursor_grabbed } pub fn grab_cursor(&mut self, grab: bool) { self.cursor_grabbed = grab; - self.window.window().set_cursor_visible(!grab); - let _ = self.window.window().set_cursor_grab(grab); + self.window.set_cursor_visible(!grab); + let _ = self.window.set_cursor_grab(grab); } /// Moves mouse cursor to center of screen @@ -1156,8 +1148,7 @@ impl Window { // the correct resolution already, load that value, otherwise filter it // in this iteration let correct_res = correct_res.unwrap_or_else(|| { - let window = self.window.window(); - window + self.window .current_monitor() .unwrap() .video_modes() @@ -1309,7 +1300,6 @@ impl Window { self .window - .window() .current_monitor().unwrap() .video_modes() // Prefer bit depth over refresh rate @@ -1321,7 +1311,7 @@ impl Window { } pub fn set_fullscreen_mode(&mut self, fullscreen: FullScreenSettings) { - let window = self.window.window(); + let window = self.window; self.fullscreen = fullscreen; window.set_fullscreen(fullscreen.enabled.then(|| match fullscreen.mode { FullscreenMode::Exclusive => { @@ -1343,20 +1333,17 @@ impl Window { pub fn logical_size(&self) -> Vec2 { let (w, h) = self .window - .window() .inner_size() - .to_logical::(self.window.window().scale_factor()) + .to_logical::(self.window.scale_factor()) .into(); Vec2::new(w, h) } pub fn set_size(&mut self, new_size: Vec2) { - self.window - .window() - .set_inner_size(winit::dpi::LogicalSize::new( - new_size.x as f64, - new_size.y as f64, - )); + self.window.set_inner_size(winit::dpi::LogicalSize::new( + new_size.x as f64, + new_size.y as f64, + )); } pub fn send_event(&mut self, event: Event) { self.events.push(event) }