diff --git a/Cargo.lock b/Cargo.lock index b761ba36a5..fbdae3293f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,11 +199,11 @@ dependencies = [ [[package]] name = "ash" -version = "0.31.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38" +checksum = "06063a002a77d2734631db74e8f4ce7148b77fe522e6bca46f2ae7774fd48112" dependencies = [ - "libloading 0.6.7", + "libloading 0.7.0", ] [[package]] @@ -693,6 +693,16 @@ dependencies = [ "objc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -1227,11 +1237,10 @@ dependencies = [ [[package]] name = "d3d12" version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a60cceb22c7c53035f8980524fdc7f17cf49681a3c154e6757d30afbec6ec4" +source = "git+https://github.com/gfx-rs/d3d12-rs?rev=be19a243b86e0bafb9937d661fc8eabb3e42b44e#be19a243b86e0bafb9937d661fc8eabb3e42b44e" dependencies = [ "bitflags", - "libloading 0.6.7", + "libloading 0.7.0", "winapi 0.3.9", ] @@ -1880,8 +1889,7 @@ dependencies = [ [[package]] name = "gfx-auxil" version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b33ecf067f2117668d91c9b0f2e5f223ebd1ffec314caa2f3de27bb580186d" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "fxhash", "gfx-hal", @@ -1891,14 +1899,13 @@ dependencies = [ [[package]] name = "gfx-backend-dx11" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f851d03c2e8f117e3702bf41201a4fafa447d5cb1276d5375870ae7573d069dd" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "arrayvec", "bitflags", "gfx-auxil", "gfx-hal", - "libloading 0.6.7", + "libloading 0.7.0", "log", "parking_lot 0.11.1", "range-alloc", @@ -1912,9 +1919,8 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5032d716a2a5f4dafb4675a794c5dc32081af8fbc7303c93ad93ff5413c6559f" +version = "0.7.0" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "arrayvec", "bit-set", @@ -1935,8 +1941,7 @@ dependencies = [ [[package]] name = "gfx-backend-empty" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07ef26a65954cfdd7b4c587f485100d1bb3b0bd6a51b02d817d6c87cca7a91" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "gfx-hal", "log", @@ -1945,18 +1950,18 @@ dependencies = [ [[package]] name = "gfx-backend-gl" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6717c50ab601efe4a669bfb44db615e3888695ac8263222aeaa702642b9fbc2" +version = "0.7.0" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "arrayvec", "bitflags", + "fxhash", "gfx-auxil", "gfx-hal", "glow", "js-sys", "khronos-egl", - "libloading 0.6.7", + "libloading 0.7.0", "log", "naga", "parking_lot 0.11.1", @@ -1969,8 +1974,7 @@ dependencies = [ [[package]] name = "gfx-backend-metal" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc54b456ece69ef49f8893269ebf24ac70969ed34ba2719c3f3abcc8fbff14e" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "arrayvec", "bitflags", @@ -1978,6 +1982,7 @@ dependencies = [ "cocoa-foundation", "copyless", "foreign-types", + "fxhash", "gfx-auxil", "gfx-hal", "log", @@ -1994,8 +1999,7 @@ dependencies = [ [[package]] name = "gfx-backend-vulkan" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabe88b1a5c91e0f969b441cc57e70364858066e4ba937deeb62065654ef9bd9" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "arrayvec", "ash", @@ -2015,8 +2019,7 @@ dependencies = [ [[package]] name = "gfx-hal" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d9cc8d3b573dda62d0baca4f02e0209786e22c562caff001d77c389008781d" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" dependencies = [ "bitflags", "naga", @@ -2162,7 +2165,6 @@ checksum = "1e7724b9aef57ea36d70faf54e0ee6265f86e41de16bed8333efdeab5b00e16b" dependencies = [ "bitflags", "gpu-alloc-types", - "tracing", ] [[package]] @@ -2183,7 +2185,6 @@ dependencies = [ "bitflags", "gpu-descriptor-types", "hashbrown", - "tracing", ] [[package]] @@ -2652,12 +2653,12 @@ dependencies = [ [[package]] name = "khronos-egl" -version = "3.0.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19cc4a81304db2a0ad69740e83cdc3a9364e3f9bd6d88a87288a4c2deec927b" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" dependencies = [ "libc", - "libloading 0.6.7", + "libloading 0.7.0", ] [[package]] @@ -2937,8 +2938,7 @@ dependencies = [ [[package]] name = "metal" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4598d719460ade24c7d91f335daf055bf2a7eec030728ce751814c50cdd6a26c" +source = "git+https://github.com/gfx-rs/metal-rs?rev=439c986eb7a9b91e88b61def2daa66e4043fcbef#439c986eb7a9b91e88b61def2daa66e4043fcbef" dependencies = [ "bitflags", "block", @@ -3065,12 +3065,12 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] name = "naga" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05089b2acdf0e6a962cdbf5e328402345a27f59fcde1a59fe97a73e8149d416f" +version = "0.3.1" +source = "git+https://github.com/gfx-rs/naga?tag=gfx-15#196523de7820d4907a14bd22517c4d572d26b0be" dependencies = [ "bit-set", "bitflags", + "codespan-reporting", "fxhash", "log", "num-traits", @@ -3951,6 +3951,12 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "profiling" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c71198452babfbba7419e716d29853c462d59da73c41485ab7dc8b4dc0c4be" + [[package]] name = "prometheus" version = "0.12.0" @@ -4153,8 +4159,7 @@ dependencies = [ [[package]] name = "range-alloc" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" +source = "git+https://github.com/gfx-rs/gfx?rev=2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45#2125c1d96b09f97faaa0d7a8a0d1c5315acc8c45" [[package]] name = "raw-window-handle" @@ -6615,18 +6620,16 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a0a0a63fac9492cfaf6e7e4bdf9729c128f1e94124b9e4cbc4004b8cb6d1d8" +version = "0.7.0" +source = "git+https://github.com/gfx-rs/wgpu-rs.git?rev=a7e03546c1584cefef5b926f923108ea2cd1c146#a7e03546c1584cefef5b926f923108ea2cd1c146" dependencies = [ "arrayvec", "js-sys", "naga", "parking_lot 0.11.1", + "profiling", "raw-window-handle", "smallvec", - "syn 1.0.65", - "tracing", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -6636,9 +6639,8 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89fa2cc5d72236461ac09c5be967012663e29cb62f1a972654cbf35e49dffa8" +version = "0.7.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=2f3b398e3887a336c963c43e7954f94cae42dd31#2f3b398e3887a336c963c43e7954f94cae42dd31" dependencies = [ "arrayvec", "bitflags", @@ -6654,12 +6656,13 @@ dependencies = [ "gfx-hal", "gpu-alloc", "gpu-descriptor", + "log", "naga", "parking_lot 0.11.1", + "profiling", "raw-window-handle", "smallvec", "thiserror", - "tracing", "wgpu-types", ] @@ -6676,8 +6679,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72fa9ba80626278fd87351555c363378d08122d7601e58319be3d6fa85a87747" +source = "git+https://github.com/gfx-rs/wgpu?rev=2f3b398e3887a336c963c43e7954f94cae42dd31#2f3b398e3887a336c963c43e7954f94cae42dd31" dependencies = [ "bitflags", ] @@ -6955,8 +6957,3 @@ checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb" dependencies = [ "chrono", ] - -[[patch.unused]] -name = "wgpu" -version = "0.7.0" -source = "git+https://github.com/gfx-rs/wgpu-rs.git?rev=a7e03546c1584cefef5b926f923108ea2cd1c146#a7e03546c1584cefef5b926f923108ea2cd1c146" diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index 6d920f6041..d5bf8f50d8 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -22,9 +22,9 @@ layout(location = 2) flat in float f_select; layout(location = 3) in vec2 f_uv_pos; layout(location = 4) in vec2 f_inst_light; -layout(set = 4, binding = 0) +layout(set = 3, binding = 0) uniform texture2D t_col_light; -layout(set = 4, binding = 1) +layout(set = 3, binding = 1) uniform sampler s_col_light; layout(location = 0) out vec4 tgt_color; diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index 5e7474ac05..543b26fd40 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -16,29 +16,22 @@ #include #include -layout(location = 0) in vec3 v_pos; -layout(location = 1) in uint v_atlas_pos; -layout(location = 2) in uint v_norm_ao; -layout(location = 3) in uint inst_pos_ori; -layout(location = 4) in vec4 inst_mat0; -layout(location = 5) in vec4 inst_mat1; -layout(location = 6) in vec4 inst_mat2; -layout(location = 7) in vec4 inst_mat3; -layout(location = 8) in vec4 inst_light; -layout(location = 9) in float inst_wind_sway; +layout(location = 0) in vec4 inst_mat0; +layout(location = 1) in vec4 inst_mat1; +layout(location = 2) in vec4 inst_mat2; +layout(location = 3) in vec4 inst_mat3; +// TODO: is there a better way to pack the various vertex attributes? +// TODO: ori is unused +layout(location = 4) in uint inst_pos_ori; +layout(location = 5) in uint inst_vert_page; // NOTE: this could fit in less bits +// TODO: do we need this many bits for light and glow? +layout(location = 6) in float inst_light; +layout(location = 7) in float inst_glow; +layout(location = 8) in float model_wind_sway; // NOTE: this only varies per model +layout(location = 9) in float model_z_scale; // NOTE: this only varies per model -struct SpriteLocals { - mat4 mat; - vec4 wind_sway; - vec4 offs; -}; - -layout(std140, set = 3, binding = 0) -uniform u_locals { - mat4 mat; - vec4 wind_sway; - vec4 offs; -}; +layout(set = 0, binding = 12) uniform utexture2D t_sprite_verts; +layout(set = 0, binding = 13) uniform sampler s_sprite_verts; layout (std140, set = 2, binding = 0) uniform u_terrain_locals { @@ -47,6 +40,7 @@ uniform u_terrain_locals { ivec4 atlas_offs; }; +// TODO: consider grouping into vec4's layout(location = 0) out vec3 f_pos; layout(location = 1) flat out vec3 f_norm; layout(location = 2) flat out float f_select; @@ -57,40 +51,64 @@ const float SCALE = 1.0 / 11.0; const float SCALE_FACTOR = pow(SCALE, 1.3) * 0.2; const int EXTRA_NEG_Z = 32768; -//const int VERT_EXTRA_NEG_Z = 128; +const int VERT_EXTRA_NEG_Z = 128; +const int VERT_PAGE_SIZE = 256; //const int VERT_PAGE_SIZE = 256; void main() { + // Matrix to transform this sprite instance from model space to chunk space mat4 inst_mat; inst_mat[0] = inst_mat0; inst_mat[1] = inst_mat1; inst_mat[2] = inst_mat2; inst_mat[3] = inst_mat3; - vec3 inst_offs = model_offs - focus_off.xyz; - f_inst_light = inst_light.xy; + // Worldpos of the chunk that this sprite is in + vec3 chunk_offs = model_offs - focus_off.xyz; - vec3 v_pos_ = wind_sway.xyz * v_pos; + f_inst_light = vec2(inst_light, inst_glow); - f_pos = (inst_mat * vec4(v_pos_, 1.0)).xyz * SCALE + inst_offs; + // Index of the vertex data in the 1D vertex texture + int vertex_index = int(gl_VertexIndex % VERT_PAGE_SIZE + inst_vert_page); + const int WIDTH = 16384; // TODO: temp + ivec2 tex_coords = ivec2(vertex_index % WIDTH, vertex_index / WIDTH); + uvec2 pos_atlas_pos_norm_ao = texelFetch(usampler2D(t_sprite_verts, s_sprite_verts), tex_coords, 0).xy; + uint v_pos_norm = pos_atlas_pos_norm_ao.x; + uint v_atlas_pos = pos_atlas_pos_norm_ao.y; + + // Expand the model vertex position bits into float values + vec3 v_pos = vec3(ivec3((uvec3(v_pos_norm) >> uvec3(0, 8, 16)) & uvec3(0xFu, 0xFu, 0x0FFFu)) - ivec3(0, 0, VERT_EXTRA_NEG_Z)); + + // Transform into chunk space and scale + f_pos = (inst_mat * vec4(v_pos, 1.0)).xyz; + // Transform info world space + f_pos += chunk_offs; // Terrain 'pop-in' effect f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); - f_pos += wind_sway.w * vec3( + // Wind sway effect + f_pos += model_wind_sway * vec3( sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35), sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25), 0.0 - //) * pow(abs(v_pos_.z), 1.3) * SCALE_FACTOR; - ) * v_pos_.z * SCALE_FACTOR; + // NOTE: could potentially replace `v_pos.z * model_z_scale` with a calculation using `inst_chunk_pos` from below + //) * pow(abs(v_pos.z * model_z_scale), 1.3) * SCALE_FACTOR; + ) * v_pos.z * model_z_scale * SCALE_FACTOR; - vec3 norm = (inst_mat[(v_norm_ao >> 1u) & 3u].xyz); - f_norm = mix(-norm, norm, v_norm_ao & 1u); + // Determine normal + vec3 norm = (inst_mat[(v_pos_norm >> 30u) & 3u].xyz); + f_norm = mix(-norm, norm, v_pos_norm >> 29u & 1u); - f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));/* + 0.5*/; + // Expand atlas tex coords to floats + // NOTE: Could defer to fragment shader if we are vert heavy + f_uv_pos = vec2((uvec2(v_atlas_pos) >> uvec2(0, 16)) & uvec2(0xFFFFu, 0xFFFFu));; + // Position of the sprite block in the chunk + // Used solely for highlighting the selected sprite + vec3 inst_chunk_pos = vec3(ivec3((uvec3(inst_pos_ori) >> uvec3(0, 6, 12)) & uvec3(0x3Fu, 0x3Fu, 0xFFFFu)) - ivec3(0, 0, EXTRA_NEG_Z)); // Select glowing - vec3 sprite_pos = floor(((inst_mat * vec4(-offs.xyz, 1)).xyz) * SCALE) + inst_offs; + vec3 sprite_pos = inst_chunk_pos + chunk_offs; f_light = (select_pos.w > 0 && select_pos.xyz == sprite_pos) ? 1.0 : 0.0; gl_Position = diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 7d30d010f5..e214ec9f52 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -45,7 +45,7 @@ i18n = {package = "veloren-i18n", path = "i18n"} # Graphics winit = {version = "0.24.0", features = ["serde"]} -wgpu = "0.7.0" +wgpu = "=0.7.0" wgpu-profiler = "0.2.1" bytemuck = { version="1.4", features=["derive"] } shaderc = "0.6.2" diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs index 2da6c4698e..980f45b818 100644 --- a/voxygen/src/render/mesh.rs +++ b/voxygen/src/render/mesh.rs @@ -28,6 +28,9 @@ impl Mesh { /// Get a mutable slice referencing the vertices of this mesh. pub fn vertices_mut(&mut self) -> &mut [V] { &mut self.verts } + /// Get a mutable vec referencing the vertices of this mesh. + pub fn vertices_mut_vec(&mut self) -> &mut Vec { &mut self.verts } + /// Push a new vertex onto the end of this mesh. pub fn push(&mut self, vert: V) { self.verts.push(vert); } diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index cf7528c90c..c27632a110 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -31,7 +31,11 @@ pub use self::{ postprocess::Locals as PostProcessLocals, shadow::{Locals as ShadowLocals, PointLightMatrix}, skybox::{create_mesh as create_skybox_mesh, Vertex as SkyboxVertex}, - sprite::{Instance as SpriteInstance, Locals as SpriteLocals, Vertex as SpriteVertex}, + sprite::{ + create_verts_texture as create_sprite_verts_texture, Instance as SpriteInstance, + SpriteGlobalsBindGroup, Vertex as SpriteVertex, + VERT_PAGE_SIZE as SPRITE_VERT_PAGE_SIZE, + }, terrain::{Locals as TerrainLocals, TerrainLayout, Vertex as TerrainVertex}, ui::{ create_quad as create_ui_quad, @@ -43,9 +47,9 @@ pub use self::{ }, renderer::{ drawer::{ - ChunkSpriteDrawer, Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer, - ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer, - TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, UiDrawer, + Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer, ParticleDrawer, + PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer, TerrainDrawer, + TerrainShadowDrawer, ThirdPassDrawer, UiDrawer, }, ColLightInfo, Renderer, }, diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index edc891d2bf..e3effc8334 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -105,7 +105,7 @@ impl LodData { array_layer_count: None, }; - renderer.create_texture_with_data_raw( + renderer.create_texture_with_data_raw::<4>( &texture_info, &view_info, &sampler_info, diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index c6ee2552a7..152bd417e2 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -253,142 +253,146 @@ pub struct GlobalsLayouts { } pub struct ColLights { - pub bind_group: wgpu::BindGroup, + pub(super) bind_group: wgpu::BindGroup, pub texture: Texture, phantom: std::marker::PhantomData, } impl GlobalsLayouts { + pub fn base_globals_layout() -> Vec { + vec![ + // Global uniform + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // Noise tex + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: false, + }, + count: None, + }, + // Light uniform + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // Shadow uniform + wgpu::BindGroupLayoutEntry { + binding: 4, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // Alt texture + wgpu::BindGroupLayoutEntry { + binding: 5, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 6, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: false, + }, + count: None, + }, + // Horizon texture + wgpu::BindGroupLayoutEntry { + binding: 7, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 8, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: false, + }, + count: None, + }, + // light shadows (ie shadows from a light?) + wgpu::BindGroupLayoutEntry { + binding: 9, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + // TODO: is this relevant? + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // lod map (t_map) + wgpu::BindGroupLayoutEntry { + binding: 10, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 11, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { + filtering: true, + comparison: false, + }, + count: None, + }, + ] + } + pub fn new(device: &wgpu::Device) -> Self { let globals = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("Globals layout"), - entries: &[ - // Global uniform - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - // Noise tex - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: false, - }, - count: None, - }, - // Light uniform - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - // Shadow uniform - wgpu::BindGroupLayoutEntry { - binding: 4, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - // Alt texture - wgpu::BindGroupLayoutEntry { - binding: 5, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 6, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: false, - }, - count: None, - }, - // Horizon texture - wgpu::BindGroupLayoutEntry { - binding: 7, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 8, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: false, - }, - count: None, - }, - // light shadows (ie shadows from a light?) - wgpu::BindGroupLayoutEntry { - binding: 9, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - // TODO: is this relevant? - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }, - // lod map (t_map) - wgpu::BindGroupLayoutEntry { - binding: 10, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 11, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - filtering: true, - comparison: false, - }, - count: None, - }, - ], + entries: &Self::base_globals_layout(), }); let col_light = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -470,6 +474,72 @@ impl GlobalsLayouts { } } + // Note: this allocation serves the purpose of not having to duplicate code + pub fn bind_base_globals<'a>( + global_model: &'a GlobalModel, + lod_data: &'a lod_terrain::LodData, + noise: &'a Texture, + ) -> Vec> { + vec![ + // Global uniform + wgpu::BindGroupEntry { + binding: 0, + resource: global_model.globals.buf().as_entire_binding(), + }, + // Noise tex + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&noise.view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&noise.sampler), + }, + // Light uniform + wgpu::BindGroupEntry { + binding: 3, + resource: global_model.lights.buf().as_entire_binding(), + }, + // Shadow uniform + wgpu::BindGroupEntry { + binding: 4, + resource: global_model.shadows.buf().as_entire_binding(), + }, + // Alt texture + wgpu::BindGroupEntry { + binding: 5, + resource: wgpu::BindingResource::TextureView(&lod_data.alt.view), + }, + wgpu::BindGroupEntry { + binding: 6, + resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler), + }, + // Horizon texture + wgpu::BindGroupEntry { + binding: 7, + resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view), + }, + wgpu::BindGroupEntry { + binding: 8, + resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler), + }, + // light shadows + wgpu::BindGroupEntry { + binding: 9, + resource: global_model.shadow_mats.buf().as_entire_binding(), + }, + // lod map (t_map) + wgpu::BindGroupEntry { + binding: 10, + resource: wgpu::BindingResource::TextureView(&lod_data.map.view), + }, + wgpu::BindGroupEntry { + binding: 11, + resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler), + }, + ] + } + pub fn bind( &self, device: &wgpu::Device, @@ -480,64 +550,7 @@ impl GlobalsLayouts { let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, layout: &self.globals, - entries: &[ - // Global uniform - wgpu::BindGroupEntry { - binding: 0, - resource: global_model.globals.buf().as_entire_binding(), - }, - // Noise tex - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::TextureView(&noise.view), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::Sampler(&noise.sampler), - }, - // Light uniform - wgpu::BindGroupEntry { - binding: 3, - resource: global_model.lights.buf().as_entire_binding(), - }, - // Shadow uniform - wgpu::BindGroupEntry { - binding: 4, - resource: global_model.shadows.buf().as_entire_binding(), - }, - // Alt texture - wgpu::BindGroupEntry { - binding: 5, - resource: wgpu::BindingResource::TextureView(&lod_data.alt.view), - }, - wgpu::BindGroupEntry { - binding: 6, - resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler), - }, - // Horizon texture - wgpu::BindGroupEntry { - binding: 7, - resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view), - }, - wgpu::BindGroupEntry { - binding: 8, - resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler), - }, - // light shadows - wgpu::BindGroupEntry { - binding: 9, - resource: global_model.shadow_mats.buf().as_entire_binding(), - }, - // lod map (t_map) - wgpu::BindGroupEntry { - binding: 10, - resource: wgpu::BindingResource::TextureView(&lod_data.map.view), - }, - wgpu::BindGroupEntry { - binding: 11, - resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler), - }, - ], + entries: &Self::bind_base_globals(global_model, lod_data, noise), }); GlobalsBindGroup { bind_group } diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index c5924bf7de..88cce391c3 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -116,7 +116,7 @@ pub fn create_col_lights( array_layer_count: None, }; - renderer.create_texture_with_data_raw( + renderer.create_texture_with_data_raw::<4>( &texture_info, &view_info, &sampler_info, diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index effcc2c405..cd82935970 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -1,47 +1,52 @@ -use super::super::{AaMode, Bound, Consts, GlobalsLayouts, TerrainLayout, Vertex as VertexTrait}; +use super::{ + super::{ + AaMode, Bound, Consts, GlobalsLayouts, Mesh, Renderer, TerrainLayout, Texture, + Vertex as VertexTrait, + }, + lod_terrain, GlobalModel, +}; use bytemuck::{Pod, Zeroable}; use core::fmt; use std::mem; use vek::*; +pub const VERT_PAGE_SIZE: u32 = 256; // pub const VERT_PAGE_SIZE: u32 = 256; #[repr(C)] #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Vertex { - pos: [f32; 3], + pos_norm: u32, // Because we try to restrict terrain sprite data to a 128×128 block // we need an offset into the texture atlas. atlas_pos: u32, - // ____BBBBBBBBGGGGGGGGRRRRRRRR - // col: u32 = "v_col", - // ...AANNN - // A = AO - // N = Normal - norm_ao: u32, + /* ____BBBBBBBBGGGGGGGGRRRRRRRR + * col: u32 = "v_col", + * .....NNN + * A = AO + * N = Normal + *norm: u32, */ } -impl fmt::Display for Vertex { +// TODO: fix? +/*impl fmt::Display for Vertex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Vertex") - .field("pos", &Vec3::::from(self.pos)) + .field("pos_norm", &Vec3::::from(self.pos)) .field( "atlas_pos", &Vec2::new(self.atlas_pos & 0xFFFF, (self.atlas_pos >> 16) & 0xFFFF), ) - .field("norm_ao", &self.norm_ao) .finish() } -} +}*/ impl Vertex { // NOTE: Limit to 16 (x) × 16 (y) × 32 (z). #[allow(clippy::collapsible_else_if)] - pub fn new( - atlas_pos: Vec2, - pos: Vec3, - norm: Vec3, /* , col: Rgb, ao: f32 */ - ) -> Self { + pub fn new(atlas_pos: Vec2, pos: Vec3, norm: Vec3) -> Self { + const VERT_EXTRA_NEG_Z: i32 = 128; // NOTE: change if number of bits changes below, also we might not need this if meshing always produces positives values for sprites (I have no idea) + let norm_bits = if norm.x != 0.0 { if norm.x < 0.0 { 0 } else { 1 } } else if norm.y != 0.0 { @@ -56,13 +61,15 @@ impl Vertex { // | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12 // | if meta { 1 } else { 0 } << 28 // | (norm_bits & 0x7) << 29, - pos: pos.into_array(), + pos_norm: ((pos.x as u32) & 0x00FF) // NOTE: temp hack, this doesn't need 8 bits + | ((pos.y as u32) & 0x00FF) << 8 + | (((pos.z as i32 + VERT_EXTRA_NEG_Z).max(0).min(1 << 12) as u32) & 0x0FFF) << 16 + | (norm_bits & 0x7) << 29, atlas_pos: ((atlas_pos.x as u32) & 0xFFFF) | ((atlas_pos.y as u32) & 0xFFFF) << 16, - norm_ao: norm_bits, } } - fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + /*fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { const ATTRIBUTES: [wgpu::VertexAttribute; 3] = wgpu::vertex_attr_array![0 => Float32x3, 1 => Uint32, 2 => Uint32]; wgpu::VertexBufferLayout { @@ -70,7 +77,11 @@ impl Vertex { step_mode: wgpu::InputStepMode::Vertex, attributes: &ATTRIBUTES, } - } + }*/ +} + +impl Default for Vertex { + fn default() -> Self { Self::new(Vec2::zero(), Vec3::zero(), Vec3::zero()) } } impl VertexTrait for Vertex { @@ -78,29 +89,29 @@ impl VertexTrait for Vertex { const STRIDE: wgpu::BufferAddress = mem::size_of::() as wgpu::BufferAddress; } -/* pub fn create_verts_buffer(renderer: &mut Renderer, mut mesh: Mesh) -> Buffer { - renderer.ensure_sufficient_index_length::(VERT_PAGE_SIZE as usize); +pub fn create_verts_texture(renderer: &mut Renderer, mut mesh: Mesh) -> Texture { + //renderer.ensure_sufficient_index_length::(VERT_PAGE_SIZE as usize); // TODO: type buffer by Usage - Buffer::new( + /*Buffer::new( &renderer.device, wgpu::BufferUsage::STORAGE, mesh.vertices(), - ) - //let mut verts = mesh.vertices_mut_vec(); - //let format = wgpu::TextureFormat::Rg32Uint; + )*/ + let mut verts = mesh.vertices_mut_vec(); + let format = wgpu::TextureFormat::Rg32Uint; // TODO: temp - //const WIDTH: u32 = 8192; - //let height = verts.len() as u32 / WIDTH; + const WIDTH: u32 = 16384; + let height = verts.len() as u32 / WIDTH; // Fill in verts to full texture size - //verts.resize_with(height as usize * WIDTH as usize, Vertex::default); + verts.resize_with(height as usize * WIDTH as usize, Vertex::default); - /*let texture_info = wgpu::TextureDescriptor { + let texture_info = wgpu::TextureDescriptor { label: Some("Sprite verts"), size: wgpu::Extent3d { width: WIDTH, height, - depth: 1, + depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: 1, @@ -136,56 +147,66 @@ impl VertexTrait for Vertex { &view_info, &sampler_info, bytemuck::cast_slice(verts), - )*/ + ) } -*/ #[repr(C)] #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Instance { - pos_ori: u32, inst_mat0: [f32; 4], inst_mat1: [f32; 4], inst_mat2: [f32; 4], inst_mat3: [f32; 4], - inst_light: [f32; 4], - inst_wind_sway: f32, + pos_ori: u32, + inst_vert_page: u32, + inst_light: f32, + inst_glow: f32, + model_wind_sway: f32, + model_z_scale: f32, } impl Instance { pub fn new( mat: Mat4, wind_sway: f32, + z_scale: f32, pos: Vec3, ori_bits: u8, light: f32, glow: f32, + vert_page: u32, ) -> Self { const EXTRA_NEG_Z: i32 = 32768; let mat_arr = mat.into_col_arrays(); Self { - pos_ori: ((pos.x as u32) & 0x003F) - | ((pos.y as u32) & 0x003F) << 6 - | (((pos + EXTRA_NEG_Z).z.max(0).min(1 << 16) as u32) & 0xFFFF) << 12 - | (u32::from(ori_bits) & 0x7) << 29, inst_mat0: mat_arr[0], inst_mat1: mat_arr[1], inst_mat2: mat_arr[2], inst_mat3: mat_arr[3], - inst_light: [light, glow, 1.0, 1.0], - inst_wind_sway: wind_sway, + pos_ori: ((pos.x as u32) & 0x003F) + | ((pos.y as u32) & 0x003F) << 6 + | (((pos.z + EXTRA_NEG_Z).max(0).min(1 << 16) as u32) & 0xFFFF) << 12 + | (u32::from(ori_bits) & 0x7) << 29, + inst_vert_page: vert_page, + inst_light: light, + inst_glow: glow, + model_wind_sway: wind_sway, + model_z_scale: z_scale, } } fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { - const ATTRIBUTES: [wgpu::VertexAttribute; 7] = wgpu::vertex_attr_array![ - 3 => Uint32, - 4 => Float32x4, - 5 => Float32x4, - 6 => Float32x4, - 7 => Float32x4, - 8 => Float32x4, + const ATTRIBUTES: [wgpu::VertexAttribute; 10] = wgpu::vertex_attr_array![ + 0 => Float32x4, + 1 => Float32x4, + 2 => Float32x4, + 3 => Float32x4, + 4 => Uint32, + 5 => Uint32, + 6 => Float32, + 7 => Float32, + 8 => Float32, 9 => Float32, ]; wgpu::VertexBufferLayout { @@ -197,10 +218,12 @@ impl Instance { } impl Default for Instance { - fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0, 1.0, 0.0) } + fn default() -> Self { Self::new(Mat4::identity(), 0.0, 0.0, Vec3::zero(), 0, 1.0, 0.0, 0) } } -#[repr(C)] +// TODO: ColLightsWrapper instead? +pub struct Locals; +/*#[repr(C)] #[derive(Copy, Clone, Debug, Zeroable, Pod)] pub struct Locals { // Each matrix performs rotatation, translation, and scaling, relative to the sprite @@ -211,8 +234,6 @@ pub struct Locals { offs: [f32; 4], } -pub type BoundLocals = Bound>; - impl Default for Locals { fn default() -> Self { Self::new(Mat4::identity(), Vec3::one(), Vec3::zero(), 0.0) } } @@ -225,16 +246,52 @@ impl Locals { offs: [offs.x, offs.y, offs.z, 0.0], } } +}*/ + +pub struct SpriteGlobalsBindGroup { + pub(in super::super) bind_group: wgpu::BindGroup, } +//pub type BoundLocals = Bound>; + pub struct SpriteLayout { - pub locals: wgpu::BindGroupLayout, + pub globals: wgpu::BindGroupLayout, + //pub locals: wgpu::BindGroupLayout, } impl SpriteLayout { pub fn new(device: &wgpu::Device) -> Self { + let mut entries = GlobalsLayouts::base_globals_layout(); + debug_assert_eq!(12, entries.len()); // To remember to adjust the bindings below + entries.extend_from_slice(&[ + // sprite verts (t_sprite_verts) + wgpu::BindGroupLayoutEntry { + binding: 12, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Uint, + view_dimension: wgpu::TextureViewDimension::D1, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 13, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::Sampler { + filtering: false, + comparison: false, + }, + count: None, + }, + ]); + Self { - locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + globals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &entries, + }), + /*locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, entries: &[ // locals @@ -250,18 +307,61 @@ impl SpriteLayout { }, // instance buffer wgpu::BindGroupLayoutEntry { - binding: 1, + binding: 1, visibility: wgpu::ShaderStage::Vertex, ty: wgpu::BufferBindingType::Buffer { - ty: wgpu::BufferBindingType:: + ty: wgpu::BufferBindingType:: } }, ], - }), + }),*/ } } - pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts) -> BoundLocals { + fn bind_globals_inner( + &self, + device: &wgpu::Device, + global_model: &GlobalModel, + lod_data: &lod_terrain::LodData, + noise: &Texture, + sprite_verts: &Texture, + ) -> wgpu::BindGroup { + let mut entries = GlobalsLayouts::bind_base_globals(global_model, lod_data, noise); + + entries.extend_from_slice(&[ + // sprite verts (t_sprite_verts) + wgpu::BindGroupEntry { + binding: 12, + resource: wgpu::BindingResource::TextureView(&sprite_verts.view), + }, + wgpu::BindGroupEntry { + binding: 13, + resource: wgpu::BindingResource::Sampler(&sprite_verts.sampler), + }, + ]); + + device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.globals, + entries: &entries, + }) + } + + pub fn bind_globals( + &self, + device: &wgpu::Device, + global_model: &GlobalModel, + lod_data: &lod_terrain::LodData, + noise: &Texture, + sprite_verts: &Texture, + ) -> SpriteGlobalsBindGroup { + let bind_group = + self.bind_globals_inner(device, global_model, lod_data, noise, sprite_verts); + + SpriteGlobalsBindGroup { bind_group } + } + + /*pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts) -> BoundLocals { let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, layout: &self.locals, @@ -275,7 +375,7 @@ impl SpriteLayout { bind_group, with: locals, } - } + }*/ } pub struct SpritePipeline { @@ -299,10 +399,11 @@ impl SpritePipeline { label: Some("Sprite pipeline layout"), push_constant_ranges: &[], bind_group_layouts: &[ - &global_layout.globals, + &layout.globals, &global_layout.shadow_textures, &terrain_layout.locals, - &layout.locals, + //&layout.locals, + // Note: mergable with globals &global_layout.col_light, ], }); @@ -321,7 +422,7 @@ impl SpritePipeline { vertex: wgpu::VertexState { module: vs_module, entry_point: "main", - buffers: &[], + buffers: &[Instance::desc()], }, primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 8a209abdba..da32f86875 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -152,7 +152,6 @@ impl Renderer { .ok_or(RenderError::CouldNotFindAdapter)?; let limits = wgpu::Limits { - max_bind_groups: 5, max_push_constant_size: 64, ..Default::default() }; @@ -1009,7 +1008,7 @@ impl Renderer { } /// Create a new immutable texture from the provided image. - pub fn create_texture_with_data_raw( + pub fn create_texture_with_data_raw( &mut self, texture_info: &wgpu::TextureDescriptor, view_info: &wgpu::TextureViewDescriptor, @@ -1018,7 +1017,7 @@ impl Renderer { ) -> Texture { let tex = Texture::new_raw(&self.device, &texture_info, &view_info, &sampler_info); - tex.update( + tex.update::( &self.device, &self.queue, [0; 2], @@ -1084,7 +1083,7 @@ impl Renderer { // texture.update(&mut self.encoder, offset, size, data) data: &[[u8; 4]], ) { - texture.update( + texture.update::<4>( &self.device, &self.queue, offset, diff --git a/voxygen/src/render/renderer/binding.rs b/voxygen/src/render/renderer/binding.rs index 9bc704cda5..ab2c9a623d 100644 --- a/voxygen/src/render/renderer/binding.rs +++ b/voxygen/src/render/renderer/binding.rs @@ -20,6 +20,21 @@ impl Renderer { .bind(&self.device, global_model, lod_data, &self.noise_tex) } + pub fn bind_sprite_globals( + &self, + global_model: &GlobalModel, + lod_data: &lod_terrain::LodData, + sprite_verts: &Texture, + ) -> sprite::SpriteGlobalsBindGroup { + self.layouts.sprite.bind_globals( + &self.device, + global_model, + lod_data, + &self.noise_tex, + sprite_verts, + ) + } + pub fn create_ui_bound_locals(&mut self, vals: &[ui::Locals]) -> ui::BoundLocals { let locals = self.create_consts(vals); self.layouts.ui.bind_locals(&self.device, locals) @@ -54,10 +69,10 @@ impl Renderer { self.layouts.shadow.bind_locals(&self.device, locals) } - pub fn create_sprite_bound_locals(&mut self, locals: &[sprite::Locals]) -> sprite::BoundLocals { - let locals = self.create_consts(locals); - self.layouts.sprite.bind_locals(&self.device, locals) - } + //pub fn create_sprite_bound_locals(&mut self, locals: &[sprite::Locals]) -> + // sprite::BoundLocals { let locals = self.create_consts(locals); + // self.layouts.sprite.bind_locals(&self.device, locals) + //} pub fn figure_bind_col_light(&self, col_light: Texture) -> ColLights { self.layouts.global.bind_col_light(&self.device, col_light) diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 059408f573..24b58239fb 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -132,6 +132,7 @@ impl<'frame> Drawer<'frame> { FirstPassDrawer { render_pass, borrow: &self.borrow, + globals: self.globals, } } @@ -406,6 +407,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> { pub struct FirstPassDrawer<'pass> { pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>, borrow: &'pass RendererBorrow<'pass>, + globals: &'pass GlobalsBindGroup, } impl<'pass> FirstPassDrawer<'pass> { @@ -459,15 +461,20 @@ impl<'pass> FirstPassDrawer<'pass> { pub fn draw_sprites<'data: 'pass>( &mut self, + globals: &'data sprite::SpriteGlobalsBindGroup, col_lights: &'data ColLights, ) -> SpriteDrawer<'_, 'pass> { let mut render_pass = self.render_pass.scope(self.borrow.device, "sprites"); render_pass.set_pipeline(&self.borrow.pipelines.sprite.pipeline); set_quad_index_buffer::(&mut render_pass, &self.borrow); - render_pass.set_bind_group(4, &col_lights.bind_group, &[]); + render_pass.set_bind_group(0, &globals.bind_group, &[]); + render_pass.set_bind_group(3, &col_lights.bind_group, &[]); - SpriteDrawer { render_pass } + SpriteDrawer { + render_pass, + globals: self.globals, + } } pub fn draw_fluid<'data: 'pass>( @@ -561,49 +568,37 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> { pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> { render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>, + globals: &'pass GlobalsBindGroup, } impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> { - pub fn in_chunk<'data: 'pass>( + pub fn draw<'data: 'pass>( &mut self, terrain_locals: &'data terrain::BoundLocals, - ) -> ChunkSpriteDrawer<'_, 'pass> { + //model: &'data Model, + //locals: &'data sprite::BoundLocals, + instances: &'data Instances, + ) { self.render_pass .set_bind_group(2, &terrain_locals.bind_group, &[]); + //self.render_pass.set_bind_group(3, &locals.bind_group, &[]); - ChunkSpriteDrawer { - render_pass: &mut self.render_pass, - } - /* //self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + //self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass .set_vertex_buffer(0, instances.buf().slice(..)); self.render_pass.draw_indexed( 0..sprite::VERT_PAGE_SIZE / 4 * 6, 0, 0..instances.count() as u32, - ); */ + ); } } -pub struct ChunkSpriteDrawer<'pass_ref, 'pass: 'pass_ref> { - render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, -} -impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> { - pub fn draw<'data: 'pass>( - &mut self, - model: &'data Model, - instances: &'data Instances, - locals: &'data sprite::BoundLocals, - ) { - self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); +impl<'pass_ref, 'pass: 'pass_ref> Drop for SpriteDrawer<'pass_ref, 'pass> { + fn drop(&mut self) { + // Reset to regular globals self.render_pass - .set_vertex_buffer(1, instances.buf().slice(..)); - self.render_pass.set_bind_group(3, &locals.bind_group, &[]); - self.render_pass.draw_indexed( - 0..model.len() as u32 / 4 * 6, - 0, - 0..instances.count() as u32, - ); + .set_bind_group(0, &self.globals.bind_group, &[]); } } diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index b55606ea60..293b47621c 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -170,7 +170,9 @@ impl Texture { /// Update a texture with the given data (used for updating the glyph cache /// texture). - pub fn update( + /// TODO: using generic here seems a bit hacky, consider storing this info + /// in the texture type or pass in wgpu::TextureFormat + pub fn update( &self, device: &wgpu::Device, queue: &wgpu::Queue, @@ -178,9 +180,10 @@ impl Texture { size: [u32; 2], data: &[u8], ) { - // Note: we only accept 4 bytes per pixel - // (enforce this in API?) - debug_assert_eq!(data.len(), size[0] as usize * size[1] as usize * 4); + debug_assert_eq!( + data.len(), + size[0] as usize * size[1] as usize * BYTES_PER_PIXEL as usize + ); // TODO: Only works for 2D images queue.write_texture( wgpu::TextureCopyViewBase { @@ -195,7 +198,7 @@ impl Texture { data, wgpu::TextureDataLayout { offset: 0, - bytes_per_row: size[0] * 4, + bytes_per_row: size[0] * BYTES_PER_PIXEL, rows_per_image: size[1], }, wgpu::Extent3d { diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index d7719dc9b2..0dabc83156 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -276,6 +276,8 @@ impl Scene { let globals_bind_group = renderer.bind_globals(&data, lod.get_data()); + let terrain = Terrain::new(renderer, &data, lod.get_data(), sprite_render_context); + Self { data, globals_bind_group, @@ -286,7 +288,7 @@ impl Scene { skybox: Skybox { model: renderer.create_model(&create_skybox_mesh()).unwrap(), }, - terrain: Terrain::new(renderer, sprite_render_context), + terrain, lod, loaded_distance: 0.0, map_bounds: Vec2::new( diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 9198cda53f..2088e79d4b 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,4 +1,5 @@ mod watcher; + pub use self::watcher::{BlocksOfInterest, Interaction}; use crate::{ @@ -8,10 +9,11 @@ use crate::{ terrain::{generate_mesh, SUNLIGHT}, }, render::{ + create_sprite_verts_texture, pipelines::{self, ColLights}, ColLightInfo, Consts, Drawer, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel, - Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals, - SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture, + Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteGlobalsBindGroup, + SpriteInstance, SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture, }, }; @@ -42,6 +44,8 @@ use treeculler::{BVol, Frustum, AABB}; use vek::*; const SPRITE_SCALE: Vec3 = Vec3::new(1.0 / 11.0, 1.0 / 11.0, 1.0 / 11.0); +const SPRITE_LOD_LEVELS: usize = 5; +const SPRITE_VERT_PAGE_SIZE: usize = 256; #[derive(Clone, Copy, Debug)] struct Visibility { @@ -82,7 +86,7 @@ pub struct TerrainChunkData { col_lights: Arc>, light_map: LightMapFn, glow_map: LightMapFn, - sprite_instances: HashMap<(SpriteKind, usize), Instances>, + sprite_instances: [Instances; SPRITE_LOD_LEVELS], locals: pipelines::terrain::BoundLocals, pub blocks_of_interest: BlocksOfInterest, @@ -116,7 +120,7 @@ pub struct MeshWorkerResponseMesh { /// mesh of a chunk. struct MeshWorkerResponse { pos: Vec2, - sprite_instances: HashMap<(SpriteKind, usize), Vec>, + sprite_instances: [Vec; SPRITE_LOD_LEVELS], /// If None, this update was requested without meshing. mesh: Option, started_tick: u64, @@ -176,7 +180,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' max_texture_size: u16, chunk: Arc, range: Aabb, - sprite_data: &HashMap<(SpriteKind, usize), Vec>, + sprite_data: &HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>, sprite_config: &SpriteSpec, ) -> MeshWorkerResponse { span!(_guard, "mesh_worker"); @@ -215,7 +219,7 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' // Extract sprite locations from volume sprite_instances: { span!(_guard, "extract sprite_instances"); - let mut instances = HashMap::new(); + let mut instances = [Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()]; for x in 0..V::RECT_SIZE.x as i32 { for y in 0..V::RECT_SIZE.y as i32 { @@ -243,23 +247,43 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' let key = (sprite, variation); // NOTE: Safe because we called sprite_config_for already. // NOTE: Safe because 0 ≤ ori < 8 - let sprite_data = &sprite_data[&key][0]; - let instance = SpriteInstance::new( - Mat4::identity() - .translated_3d(sprite_data.offset) + let sprite_data_lod_0 = &sprite_data[&key][0]; + let mat = Mat4::identity() + // NOTE: offset doesn't change with lod level + // TODO: pull out of per lod level info or remove lod levels + // for sprites entirely + .translated_3d(sprite_data_lod_0.offset) + // Lod scaling etc is baked during meshing + .scaled_3d(SPRITE_SCALE) .rotated_z(f32::consts::PI * 0.25 * ori as f32) .translated_3d( (rel_pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)) - / SPRITE_SCALE, - ), - cfg.wind_sway, - rel_pos, - ori, - light_map(wpos), - glow_map(wpos), - ); + ); + let light = light_map(wpos); + let glow = glow_map(wpos); - instances.entry(key).or_insert(Vec::new()).push(instance); + for lod_level in 0..SPRITE_LOD_LEVELS { + let sprite_data = &sprite_data[&key][lod_level]; + // Add an instance for each page in the sprite model + for page in sprite_data.vert_pages.clone() { + // TODO: could be more efficient to create once and clone while + // modifying vert_page + let instance = SpriteInstance::new( + mat, + cfg.wind_sway, + sprite_data.scale.z, + rel_pos, + ori, + light, + glow, + page, + ); + instances[lod_level].push(instance); + } + } + + //instances.entry(key).or_insert(Vec::new()). + // push(instance); } } } @@ -273,11 +297,18 @@ fn mesh_worker + RectRasterableVol + ReadVol + Debug + ' } } +// TODO: may be unecessary +struct ChunkSpriteData { + // Instances + model: Instances, +} + struct SpriteData { - /* mat: Mat4, */ - locals: pipelines::sprite::BoundLocals, - model: Model, - /* scale: Vec3, */ + // Sprite vert page ranges that need to be drawn + vert_pages: core::ops::Range, + // Scale + scale: Vec3, + // Offset offset: Vec3, } @@ -328,8 +359,10 @@ pub struct Terrain { mesh_recv_overflow: f32, // GPU data - sprite_data: Arc>>, - sprite_col_lights: ColLights, + // Maps sprite kind + variant to data detailing how to render it + sprite_data: Arc>, + sprite_globals: SpriteGlobalsBindGroup, + sprite_col_lights: Arc>, /// As stated previously, this is always the very latest texture into which /// we allocate. Code cannot assume that this is the assigned texture /// for any particular chunk; look at the `texture` field in @@ -347,8 +380,10 @@ impl TerrainChunkData { #[derive(Clone)] pub struct SpriteRenderContext { sprite_config: Arc, - sprite_data: Arc>>, - sprite_col_lights: Texture, /* */ + // Maps sprite kind + variant to data detailing how to render it + sprite_data: Arc>, + sprite_col_lights: Arc>, + sprite_verts_texture: Arc, } pub type SpriteRenderContextLazy = Box SpriteRenderContext>; @@ -358,16 +393,11 @@ impl SpriteRenderContext { pub fn new(renderer: &mut Renderer) -> SpriteRenderContextLazy { let max_texture_size = renderer.max_texture_size(); - struct SpriteDataResponse { - locals: [SpriteLocals; 8], - model: Mesh, - offset: Vec3, - } - struct SpriteWorkerResponse { sprite_config: Arc, - sprite_data: HashMap<(SpriteKind, usize), Vec>, + sprite_data: HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>, sprite_col_lights: ColLightInfo, + sprite_mesh: Mesh, } let join_handle = std::thread::spawn(move || { @@ -377,7 +407,8 @@ impl SpriteRenderContext { 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 mut locals_buffer = [SpriteLocals::default(); 8]; + let mut sprite_mesh = Mesh::new(); let sprite_config_ = &sprite_config; // NOTE: Tracks the start vertex of the next model to be meshed. let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter() @@ -420,62 +451,68 @@ impl SpriteRenderContext { scale } }); - let sprite_mat: Mat4 = - Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE); - move |greedy: &mut GreedyMesh| { - ( - (kind, variation), - scaled - .iter() - .map(|&lod_scale_orig| { - let lod_scale = model_scale - * if lod_scale_orig == 1.0 { - Vec3::broadcast(1.0) - } else { - lod_axes * lod_scale_orig - + lod_axes.map(|e| { - if e == 0.0 { 1.0 } else { 0.0 } - }) - }; - // Mesh generation exclusively acts using side effects; - // it has no - // interesting return value, but updates the mesh. - let mut opaque_mesh = Mesh::new(); - generate_mesh_base_vol_sprite( - Segment::from(&model.read().0).scaled_by(lod_scale), - (greedy, &mut opaque_mesh, false), - ); + //let sprite_mat: Mat4 = + // Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE); + move |greedy: &mut GreedyMesh, sprite_mesh: &mut Mesh| { + let lod_sprite_data = scaled.map(|lod_scale_orig| { + let lod_scale = model_scale + * if lod_scale_orig == 1.0 { + Vec3::broadcast(1.0) + } else { + lod_axes * lod_scale_orig + + lod_axes.map(|e| if e == 0.0 { 1.0 } else { 0.0 }) + }; - let sprite_scale = Vec3::one() / lod_scale; - let sprite_mat: Mat4 = - 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, - ); - *locals = SpriteLocals::new( - sprite_mat, - sprite_scale, - offset, - wind_sway, - ); - }, - ); + // Get starting page count of opaque mesh + let start_page_num = + sprite_mesh.vertices().len() / SPRITE_VERT_PAGE_SIZE; + // Mesh generation exclusively acts using side effects; it + // has no interesting return value, but updates the mesh. + generate_mesh_base_vol_sprite( + Segment::from(&model.read().0).scaled_by(lod_scale), + (greedy, sprite_mesh, false), + ); + // Get the number of pages after the model was meshed + let end_page_num = + (sprite_mesh.vertices().len() + SPRITE_VERT_PAGE_SIZE - 1) + / SPRITE_VERT_PAGE_SIZE; + // Fill the current last page up with degenerate verts + sprite_mesh.vertices_mut_vec().resize_with( + end_page_num * SPRITE_VERT_PAGE_SIZE, + SpriteVertex::default, + ); - SpriteDataResponse { - model: opaque_mesh, + let sprite_scale = Vec3::one() / lod_scale; + //let sprite_mat: Mat4 = + // 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, + ); + *locals = SpriteLocals::new( + sprite_mat, + sprite_scale, offset, - locals: locals_buffer, - } - }) - .collect::>(), - ) + wind_sway, + ); + }, + );*/ + + SpriteData { + vert_pages: start_page_num as u32..end_page_num as u32, + scale: sprite_scale, + offset, + //locals: locals_buffer, + } + }); + + ((kind, variation), lod_sprite_data) } }, ) }) - .map(|mut f| f(&mut greedy)) + .map(|mut f| f(&mut greedy, &mut sprite_mesh)) .collect(); let sprite_col_lights = greedy.finalize(); @@ -484,6 +521,7 @@ impl SpriteRenderContext { sprite_config, sprite_data, sprite_col_lights, + sprite_mesh, } }); @@ -498,6 +536,7 @@ impl SpriteRenderContext { sprite_config, sprite_data, sprite_col_lights, + sprite_mesh, } = join_handle .take() .expect( @@ -507,39 +546,19 @@ impl SpriteRenderContext { .join() .unwrap(); - let sprite_data = sprite_data - .into_iter() - .map(|(key, models)| { - ( - key, - models - .into_iter() - .map( - |SpriteDataResponse { - locals: locals_buffer, - model, - offset, - }| { - SpriteData { - locals: renderer.create_sprite_bound_locals(&locals_buffer), - model: renderer.create_model(&model).expect( - "Failed to upload sprite model data to the GPU!", - ), - offset, - } - }, - ) - .collect(), - ) - }) - .collect(); let sprite_col_lights = pipelines::shadow::create_col_lights(renderer, &sprite_col_lights); + let sprite_col_lights = renderer.sprite_bind_col_light(sprite_col_lights); + + // Write sprite model to a 1D texture + let sprite_verts_texture = create_sprite_verts_texture(renderer, sprite_mesh); Self { + // TODO: this are all Arcs, would it makes sense to factor out the Arc? sprite_config: Arc::clone(&sprite_config), sprite_data: Arc::new(sprite_data), - sprite_col_lights, + sprite_col_lights: Arc::new(sprite_col_lights), + sprite_verts_texture: Arc::new(sprite_verts_texture), } }; Box::new(move |renderer| init.get_or_init(|| closure(renderer)).clone()) @@ -547,7 +566,12 @@ impl SpriteRenderContext { } impl Terrain { - pub fn new(renderer: &mut Renderer, sprite_render_context: SpriteRenderContext) -> Self { + pub fn new( + renderer: &mut Renderer, + global_model: &GlobalModel, + lod_data: &LodData, + sprite_render_context: SpriteRenderContext, + ) -> Self { // Create a new mpsc (Multiple Produced, Single Consumer) pair for communicating // with worker threads that are meshing chunks. let (send, recv) = channel::unbounded(); @@ -566,8 +590,13 @@ impl Terrain { mesh_todos_active: Arc::new(AtomicU64::new(0)), mesh_recv_overflow: 0.0, sprite_data: sprite_render_context.sprite_data, - sprite_col_lights: renderer - .sprite_bind_col_light(sprite_render_context.sprite_col_lights), + sprite_col_lights: sprite_render_context.sprite_col_lights, + sprite_globals: renderer.bind_sprite_globals( + global_model, + lod_data, + &sprite_render_context.sprite_verts_texture, + ), + col_lights: Arc::new(col_lights), waves: { let waves_tex = renderer .create_texture( @@ -579,7 +608,6 @@ impl Terrain { renderer.fluid_bind_waves(waves_tex) }, - col_lights: Arc::new(col_lights), phantom: PhantomData, } } @@ -1082,18 +1110,20 @@ impl Terrain { // data structure (convert the mesh to a model first of course). Some(todo) if response.started_tick <= todo.started_tick => { let started_tick = todo.started_tick; - let sprite_instances = response - .sprite_instances - .into_iter() - .map(|(kind, instances)| { - ( - kind, - renderer - .create_instances(&instances) - .expect("Failed to upload chunk sprite instances to the GPU!"), - ) - }) - .collect(); + let sprite_instances = { + let mut iter = response.sprite_instances.iter().map(|instances| { + renderer + .create_instances(instances) + .expect("Failed to upload chunk sprite instances to the GPU!") + }); + [ + iter.next().unwrap(), + iter.next().unwrap(), + iter.next().unwrap(), + iter.next().unwrap(), + iter.next().unwrap(), + ] + }; if let Some(mesh) = response.mesh { // Full update, insert the whole chunk. @@ -1509,15 +1539,21 @@ impl Terrain { span!(guard, "Terrain sprites"); let chunk_size = V::RECT_SIZE.map(|e| e as f32); let chunk_mag = (chunk_size * (f32::consts::SQRT_2 * 0.5)).magnitude_squared(); - let mut sprite_drawer = drawer.draw_sprites(&self.sprite_col_lights); + + let sprite_low_detail_distance = sprite_render_distance * 0.75; + let sprite_mid_detail_distance = sprite_render_distance * 0.5; + let sprite_hid_detail_distance = sprite_render_distance * 0.35; + let sprite_high_detail_distance = sprite_render_distance * 0.15; + + let mut sprite_drawer = drawer.draw_sprites(&self.sprite_globals, &self.sprite_col_lights); chunk_iter .clone() .filter(|(_, c)| c.visible.is_visible()) .for_each(|(pos, chunk)| { - let sprite_low_detail_distance = sprite_render_distance * 0.75; - let sprite_mid_detail_distance = sprite_render_distance * 0.5; - let sprite_hid_detail_distance = sprite_render_distance * 0.35; - let sprite_high_detail_distance = sprite_render_distance * 0.15; + // Skip chunk if it has no sprites + if chunk.sprite_instances[0].count() == 0 { + return; + } let chunk_center = pos.map2(chunk_size, |e, sz| (e as f32 + 0.5) * sz); let focus_dist_sqrd = Vec2::from(focus_pos).distance_squared(chunk_center); @@ -1535,31 +1571,27 @@ impl Terrain { chunk_center + chunk_size.x * 0.5 - chunk_size.y * 0.5, )); if focus_dist_sqrd < sprite_render_distance.powi(2) { - // TODO: skip if sprite_instances is empty - let mut chunk_sprite_drawer = sprite_drawer.in_chunk(&chunk.locals); - for (kind, instances) in (&chunk.sprite_instances).into_iter() { - let SpriteData { model, locals, .. } = if kind - .0 - .elim_case_pure(&self.sprite_config.0) - .as_ref() - .map(|config| config.wind_sway >= 0.4) - .unwrap_or(false) - && dist_sqrd <= chunk_mag - || dist_sqrd < sprite_high_detail_distance.powi(2) - { - &self.sprite_data[&kind][0] - } else if dist_sqrd < sprite_hid_detail_distance.powi(2) { - &self.sprite_data[&kind][1] - } else if dist_sqrd < sprite_mid_detail_distance.powi(2) { - &self.sprite_data[&kind][2] - } else if dist_sqrd < sprite_low_detail_distance.powi(2) { - &self.sprite_data[&kind][3] - } else { - &self.sprite_data[&kind][4] - }; + let lod_level = /*let SpriteData { model, locals, .. } = if kind + .0 + .elim_case_pure(&self.sprite_config.0) + .as_ref() + .map(|config| config.wind_sway >= 0.4) + .unwrap_or(false) + &&*/ if dist_sqrd <= chunk_mag + || dist_sqrd < sprite_high_detail_distance.powi(2) + { + 0 + } else if dist_sqrd < sprite_hid_detail_distance.powi(2) { + 1 + } else if dist_sqrd < sprite_mid_detail_distance.powi(2) { + 2 + } else if dist_sqrd < sprite_low_detail_distance.powi(2) { + 3 + } else { + 4 + }; - chunk_sprite_drawer.draw(model, instances, locals); - } + sprite_drawer.draw(&chunk.locals, &chunk.sprite_instances[lod_level]); } }); drop(sprite_drawer); diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 45da3d9079..3b55a13ef4 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -601,7 +601,7 @@ impl Window { let scale_factor = window.scale_factor(); - let key_layout = match KeyLayout::new_from_window(window.window()) { + let key_layout = match KeyLayout::new_from_window(&window) { Ok(kl) => Some(kl), Err(err) => { warn!(