From aee4779c50f22dceaef946218260caf34011a757 Mon Sep 17 00:00:00 2001 From: Chris Biscardi Date: Thu, 4 Jul 2024 21:11:17 -0700 Subject: [PATCH] Update to 0.14.0 (#537) * Update to 0.14.0-rc.2 * [12997](https://github.com/bevyengine/bevy/pull/12997): rename `multi-threaded` to `multi_threaded` * RenderAssets is now RenderAssets Implemented in [12827](https://github.com/bevyengine/bevy/pull/12827) * FloatOrd is now in bevy_math implemented in [12732](https://github.com/bevyengine/bevy/pull/12732) * convert Transparent2d::dynamic_offset to extra_index [12889](https://github.com/bevyengine/bevy/pull/12889) Gpu Frustum Culling removed the dynamic_offset of Transparent2d and it became `extra_index` with the special value `PhaseItemExtraIndex::NONE`, which indicates the `None` that was here previously * RenderPhase -> ViewSortedRenderPhases [12453](https://github.com/StarArawn/bevy_ecs_tilemap/pull/bevyengine/bevy#12453): Render phases are now binned or sorted. Following the changes in the `mesh2d_manual` [example](https://github.com/bevyengine/bevy/blob/ecdd1624f302c5f71aaed95b0984cbbecf8880b7/examples/2d/mesh2d_manual.rs#L357-L358): use the `ViewSortedRenderPhases` resource. * get_sub_app_mut is now an Option in [9202](https://github.com/StarArawn/bevy_ecs_tilemap/pull/bevyengine/bevy/pull/9202) SubApp access has changed * GpuImage::size f32 -> u32 via UVec2 [11698](https://github.com/bevyengine/bevy/pull/11698) changed `GpuImage::size` to `UVec2`. Right above this, `Extent3d` does the same thing, so I'm taking a small leap and assuming can `as`. * GpuMesh::primitive_topology -> key_bits/BaseMeshPipeline [12791](https://github.com/bevyengine/bevy/pull/12791) the `primitive_topology` field on `GpuMesh` was removed in favor of `key_bits` which can be constructed using `BaseMeshPipeline::from_primitive_topology` * RenderChunk2d::prepare requires &mut MeshVertexBufferLayouts now [12216](https://github.com/bevyengine/bevy/pull/12216) introduced an argument `&mut MeshVertexBufferLayouts` to `get_mesh_vertex_buffer_layout`, which bevy_ecs_tilemap calls in `RenderChunk2d::prepare` * into_linear_f32 -> color.0.linear().to_f32_array(), [12163](https://github.com/bevyengine/bevy/pull/12163) bevy_color was created and Color handling has changed. Specifically Color::as_linear_rgba_f32 has been removed. LinearRgba is now its own type that can be accessed via [`linear()`](https://docs.rs/bevy/0.14.0-rc.2/bevy/color/enum.Color.html#method.linear) and then converted. * Must specify type of VisibleEntities when accessing [12582](https://github.com/bevyengine/bevy/pull/12582) divided `VisibleEntities` into separate lists. So now we have to specify which kind of entity we want. I think we want the Mesh here, and I think we can get rid of the `.index` calls on Entity since Entity [already compares bits](https://docs.rs/bevy_ecs/0.14.0-rc.2/src/bevy_ecs/entity/mod.rs.html#173) for optimized codegen purposes. Waiting to do that until the other changes are in though so as to not change functionality until post-upgrade. * app.world access is functions now - [9202](https://github.com/bevyengine/bevy/pull/9202) changed world access to functions. [relevent line](https://github.com/bevyengine/bevy/pull/9202/files#diff-b2fba3a0c86e496085ce7f0e3f1de5960cb754c7d215ed0f087aa556e529f97fR640) - This also surfaced [12655](https://github.com/bevyengine/bevy/pull/12655) which removed `Into>` for `Handle`. using a reference or .id() is the solution here. * We don't need `World::cell`, and it doesn't exist anymore In [12551](https://github.com/bevyengine/bevy/pull/12551) `WorldCell` was removed. ...but it turns out we don't need it or its replacement anyway. * examples error out unless this bevy bug is addressed with these features being added https://github.com/bevyengine/bevy/issues/13728 * check_visibility is required for the entity that is renderable As a result of [12582](https://github.com/bevyengine/bevy/pull/12582) `check_visibility` must be implemented for the "renderable" tilemap entities. Doing this is trivial by taking advantage of the existing `check_visibility` type arguments, which accept a [`QF: QueryFilter + 'static`](https://docs.rs/bevy/0.14.0-rc.2/bevy/render/view/fn.check_visibility.html). The same `QueryFilter`` is used when checking `VisibleEntities`. I've chosen `With, With, With)>; ``` * view.view_proj -> view.clip_from_world [13289](https://github.com/bevyengine/bevy/pull/13489) introduced matrix naming changes, including `view_proj` which becomes `clip_from_world` * color changes to make tests runnable * clippy fix * Update Cargo.toml Co-authored-by: Rob Parrett * Update Cargo.toml Co-authored-by: Rob Parrett * final clippy fixes * Update Cargo.toml Co-authored-by: Rob Parrett * Simplify async loading in ldtk/tiled helpers See Bevy #12550 * remove second allow lint * rc.3 bump * bump version for major release * remove unused features --------- Co-authored-by: Rob Parrett --- Cargo.toml | 14 ++- examples/colors.rs | 8 +- examples/helpers/ldtk.rs | 69 ++++++----- examples/helpers/tiled.rs | 149 ++++++++++++------------ examples/hex_neighbors.rs | 8 +- examples/hex_neighbors_radius_chunks.rs | 6 +- examples/mouse_to_tile.rs | 4 +- src/render/chunk.rs | 23 +++- src/render/extract.rs | 2 +- src/render/material.rs | 42 +++---- src/render/mod.rs | 25 +++- src/render/pipeline.rs | 1 - src/render/prepare.rs | 5 +- src/render/shaders/tilemap_vertex.wgsl | 2 +- src/render/texture_array_cache.rs | 11 +- 15 files changed, 197 insertions(+), 172 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0377fa68..1dd8dc01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bevy_ecs_tilemap" description = "A tilemap rendering plugin for bevy which is more ECS friendly by having an entity per tile." -version = "0.12.0" +version = "0.14.0" authors = ["John Mitchell"] homepage = "https://github.com/StarArawn/bevy_ecs_tilemap" repository = "https://github.com/StarArawn/bevy_ecs_tilemap" @@ -16,7 +16,7 @@ render = [] serde = ["dep:serde"] [dependencies] -bevy = { version = "0.13", default-features = false, features = [ +bevy = { version = "0.14.0", default-features = false, features = [ "bevy_core_pipeline", "bevy_render", "bevy_asset", @@ -35,7 +35,7 @@ tiled = { version = "0.11.0", default-features = false } thiserror = { version = "1.0" } [dev-dependencies.bevy] -version = "0.13" +version = "0.14.0" default-features = false features = [ "bevy_core_pipeline", @@ -47,11 +47,12 @@ features = [ "bevy_text", "bevy_sprite", #"file_watcher", - "multi-threaded", + "multi_threaded", + "webgl2", ] [target.'cfg(unix)'.dev-dependencies.bevy] -version = "0.13" +version = "0.14.0" default-features = false features = [ "bevy_core_pipeline", @@ -63,7 +64,8 @@ features = [ "x11", "bevy_text", "bevy_sprite", - "multi-threaded", + "multi_threaded", + "webgl2", ] diff --git a/examples/colors.rs b/examples/colors.rs index 95548281..6b33e878 100644 --- a/examples/colors.rs +++ b/examples/colors.rs @@ -29,7 +29,7 @@ fn startup(mut commands: Commands, asset_server: Res) { TileTextureIndex(5), TilePos { x: 0, y: 0 }, quadrant_size, - Color::rgba(1.0, 0.0, 0.0, 1.0), + Color::srgba(1.0, 0.0, 0.0, 1.0), tilemap_id, &mut commands, &mut tile_storage, @@ -42,7 +42,7 @@ fn startup(mut commands: Commands, asset_server: Res) { y: 0, }, quadrant_size, - Color::rgba(0.0, 1.0, 0.0, 1.0), + Color::srgba(0.0, 1.0, 0.0, 1.0), tilemap_id, &mut commands, &mut tile_storage, @@ -55,7 +55,7 @@ fn startup(mut commands: Commands, asset_server: Res) { y: QUADRANT_SIDE_LENGTH, }, quadrant_size, - Color::rgba(0.0, 0.0, 1.0, 1.0), + Color::srgba(0.0, 0.0, 1.0, 1.0), tilemap_id, &mut commands, &mut tile_storage, @@ -68,7 +68,7 @@ fn startup(mut commands: Commands, asset_server: Res) { y: QUADRANT_SIDE_LENGTH, }, quadrant_size, - Color::rgba(1.0, 1.0, 0.0, 1.0), + Color::srgba(1.0, 1.0, 0.0, 1.0), tilemap_id, &mut commands, &mut tile_storage, diff --git a/examples/helpers/ldtk.rs b/examples/helpers/ldtk.rs index d3125c3d..e515ed01 100644 --- a/examples/helpers/ldtk.rs +++ b/examples/helpers/ldtk.rs @@ -14,7 +14,6 @@ use bevy::{ use bevy::{ asset::{AssetLoader, AssetPath, LoadContext}, prelude::*, - utils::BoxedFuture, }; use bevy_ecs_tilemap::map::TilemapType; @@ -62,45 +61,43 @@ impl AssetLoader for LdtkLoader { type Settings = (); type Error = LdtkAssetLoaderError; - fn load<'a>( + async fn load<'a>( &'a self, - reader: &'a mut Reader, + reader: &'a mut Reader<'_>, _settings: &'a Self::Settings, - load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes).await?; - - let project: ldtk_rust::Project = serde_json::from_slice(&bytes).map_err(|e| { - std::io::Error::new( - ErrorKind::Other, - format!("Could not read contents of Ldtk map: {e}"), - ) - })?; - let dependencies: Vec<(i64, AssetPath)> = project - .defs - .tilesets - .iter() - .filter_map(|tileset| { - tileset.rel_path.as_ref().map(|rel_path| { - ( - tileset.uid, - load_context.path().parent().unwrap().join(rel_path).into(), - ) - }) + load_context: &'a mut LoadContext<'_>, + ) -> Result { + let mut bytes = Vec::new(); + reader.read_to_end(&mut bytes).await?; + + let project: ldtk_rust::Project = serde_json::from_slice(&bytes).map_err(|e| { + std::io::Error::new( + ErrorKind::Other, + format!("Could not read contents of Ldtk map: {e}"), + ) + })?; + let dependencies: Vec<(i64, AssetPath)> = project + .defs + .tilesets + .iter() + .filter_map(|tileset| { + tileset.rel_path.as_ref().map(|rel_path| { + ( + tileset.uid, + load_context.path().parent().unwrap().join(rel_path).into(), + ) }) - .collect(); + }) + .collect(); - let ldtk_map = LdtkMap { - project, - tilesets: dependencies - .iter() - .map(|dep| (dep.0, load_context.load(dep.1.clone()))) - .collect(), - }; - Ok(ldtk_map) - }) + let ldtk_map = LdtkMap { + project, + tilesets: dependencies + .iter() + .map(|dep| (dep.0, load_context.load(dep.1.clone()))) + .collect(), + }; + Ok(ldtk_map) } fn extensions(&self) -> &[&str] { diff --git a/examples/helpers/tiled.rs b/examples/helpers/tiled.rs index e36f9a1a..4e5172ff 100644 --- a/examples/helpers/tiled.rs +++ b/examples/helpers/tiled.rs @@ -25,7 +25,7 @@ use bevy::{ Res, Transform, Update, }, reflect::TypePath, - utils::{BoxedFuture, HashMap}, + utils::HashMap, }; use bevy_ecs_tilemap::prelude::*; @@ -104,90 +104,87 @@ impl AssetLoader for TiledLoader { type Settings = (); type Error = TiledAssetLoaderError; - fn load<'a>( + async fn load<'a>( &'a self, - reader: &'a mut Reader, + reader: &'a mut Reader<'_>, _settings: &'a Self::Settings, - load_context: &'a mut bevy::asset::LoadContext, - ) -> BoxedFuture<'a, Result> { - Box::pin(async move { - let mut bytes = Vec::new(); - reader.read_to_end(&mut bytes).await?; - - let mut loader = tiled::Loader::with_cache_and_reader( - tiled::DefaultResourceCache::new(), - BytesResourceReader::new(&bytes), - ); - let map = loader.load_tmx_map(load_context.path()).map_err(|e| { - std::io::Error::new(ErrorKind::Other, format!("Could not load TMX map: {e}")) - })?; - - let mut tilemap_textures = HashMap::default(); - #[cfg(not(feature = "atlas"))] - let mut tile_image_offsets = HashMap::default(); - - for (tileset_index, tileset) in map.tilesets().iter().enumerate() { - let tilemap_texture = match &tileset.image { - None => { - #[cfg(feature = "atlas")] - { - log::info!("Skipping image collection tileset '{}' which is incompatible with atlas feature", tileset.name); - continue; - } + load_context: &'a mut bevy::asset::LoadContext<'_>, + ) -> Result { + let mut bytes = Vec::new(); + reader.read_to_end(&mut bytes).await?; + + let mut loader = tiled::Loader::with_cache_and_reader( + tiled::DefaultResourceCache::new(), + BytesResourceReader::new(&bytes), + ); + let map = loader.load_tmx_map(load_context.path()).map_err(|e| { + std::io::Error::new(ErrorKind::Other, format!("Could not load TMX map: {e}")) + })?; + + let mut tilemap_textures = HashMap::default(); + #[cfg(not(feature = "atlas"))] + let mut tile_image_offsets = HashMap::default(); + + for (tileset_index, tileset) in map.tilesets().iter().enumerate() { + let tilemap_texture = match &tileset.image { + None => { + #[cfg(feature = "atlas")] + { + log::info!("Skipping image collection tileset '{}' which is incompatible with atlas feature", tileset.name); + continue; + } - #[cfg(not(feature = "atlas"))] - { - let mut tile_images: Vec> = Vec::new(); - for (tile_id, tile) in tileset.tiles() { - if let Some(img) = &tile.image { - // The load context path is the TMX file itself. If the file is at the root of the - // assets/ directory structure then the tmx_dir will be empty, which is fine. - let tmx_dir = load_context - .path() - .parent() - .expect("The asset load context was empty."); - let tile_path = tmx_dir.join(&img.source); - let asset_path = AssetPath::from(tile_path); - log::info!("Loading tile image from {asset_path:?} as image ({tileset_index}, {tile_id})"); - let texture: Handle = - load_context.load(asset_path.clone()); - tile_image_offsets - .insert((tileset_index, tile_id), tile_images.len() as u32); - tile_images.push(texture.clone()); - } + #[cfg(not(feature = "atlas"))] + { + let mut tile_images: Vec> = Vec::new(); + for (tile_id, tile) in tileset.tiles() { + if let Some(img) = &tile.image { + // The load context path is the TMX file itself. If the file is at the root of the + // assets/ directory structure then the tmx_dir will be empty, which is fine. + let tmx_dir = load_context + .path() + .parent() + .expect("The asset load context was empty."); + let tile_path = tmx_dir.join(&img.source); + let asset_path = AssetPath::from(tile_path); + log::info!("Loading tile image from {asset_path:?} as image ({tileset_index}, {tile_id})"); + let texture: Handle = load_context.load(asset_path.clone()); + tile_image_offsets + .insert((tileset_index, tile_id), tile_images.len() as u32); + tile_images.push(texture.clone()); } - - TilemapTexture::Vector(tile_images) } + + TilemapTexture::Vector(tile_images) } - Some(img) => { - // The load context path is the TMX file itself. If the file is at the root of the - // assets/ directory structure then the tmx_dir will be empty, which is fine. - let tmx_dir = load_context - .path() - .parent() - .expect("The asset load context was empty."); - let tile_path = tmx_dir.join(&img.source); - let asset_path = AssetPath::from(tile_path); - let texture: Handle = load_context.load(asset_path.clone()); - - TilemapTexture::Single(texture.clone()) - } - }; + } + Some(img) => { + // The load context path is the TMX file itself. If the file is at the root of the + // assets/ directory structure then the tmx_dir will be empty, which is fine. + let tmx_dir = load_context + .path() + .parent() + .expect("The asset load context was empty."); + let tile_path = tmx_dir.join(&img.source); + let asset_path = AssetPath::from(tile_path); + let texture: Handle = load_context.load(asset_path.clone()); + + TilemapTexture::Single(texture.clone()) + } + }; - tilemap_textures.insert(tileset_index, tilemap_texture); - } + tilemap_textures.insert(tileset_index, tilemap_texture); + } - let asset_map = TiledMap { - map, - tilemap_textures, - #[cfg(not(feature = "atlas"))] - tile_image_offsets, - }; + let asset_map = TiledMap { + map, + tilemap_textures, + #[cfg(not(feature = "atlas"))] + tile_image_offsets, + }; - log::info!("Loaded map: {}", load_context.path().display()); - Ok(asset_map) - }) + log::info!("Loaded map: {}", load_context.path().display()); + Ok(asset_map) } fn extensions(&self) -> &[&str] { diff --git a/examples/hex_neighbors.rs b/examples/hex_neighbors.rs index c3c8ccb5..9aa2f1bd 100644 --- a/examples/hex_neighbors.rs +++ b/examples/hex_neighbors.rs @@ -1,5 +1,5 @@ -use bevy::math::Vec4Swizzles; use bevy::prelude::*; +use bevy::{color::palettes, math::Vec4Swizzles}; use bevy_ecs_tilemap::helpers::hex_grid::neighbors::{HexDirection, HexNeighbors}; use bevy_ecs_tilemap::prelude::*; mod helpers; @@ -315,7 +315,7 @@ fn hover_highlight_tile_label( if let Ok(label) = tile_label_q.get(tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::RED; + section.style.color = palettes::tailwind::RED_600.into(); } commands.entity(tile_entity).insert(Hovered); } @@ -371,7 +371,7 @@ fn highlight_neighbor_label( if let Ok(label) = tile_label_q.get(tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::BLUE; + section.style.color = palettes::tailwind::BLUE_600.into(); } commands.entity(tile_entity).insert(NeighborHighlight); } @@ -412,7 +412,7 @@ fn highlight_neighbor_label( if let Ok(label) = tile_label_q.get(tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::GREEN; + section.style.color = palettes::tailwind::GREEN_600.into(); } commands.entity(tile_entity).insert(NeighborHighlight); } diff --git a/examples/hex_neighbors_radius_chunks.rs b/examples/hex_neighbors_radius_chunks.rs index 96dd4579..fad33261 100644 --- a/examples/hex_neighbors_radius_chunks.rs +++ b/examples/hex_neighbors_radius_chunks.rs @@ -1,4 +1,4 @@ -use bevy::{math::Vec4Swizzles, prelude::*}; +use bevy::{color::palettes, math::Vec4Swizzles, prelude::*}; use bevy_ecs_tilemap::{helpers::hex_grid::offset::*, prelude::*}; mod helpers; use helpers::camera::movement as camera_movement; @@ -430,7 +430,7 @@ fn hover_highlight_tile_label( if let Ok(label) = tile_label_q.get(tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::RED; + section.style.color = palettes::tailwind::RED_600.into(); } commands.entity(tile_entity).insert(Hovered); } @@ -511,7 +511,7 @@ fn highlight_neighbor_labels( if let Ok(label) = tile_label_q.get(*tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::BLUE; + section.style.color = palettes::tailwind::BLUE_600.into(); } commands.entity(*tile_entity).insert(NeighborHighlight); } diff --git a/examples/mouse_to_tile.rs b/examples/mouse_to_tile.rs index ac432501..9ea13ec2 100644 --- a/examples/mouse_to_tile.rs +++ b/examples/mouse_to_tile.rs @@ -1,4 +1,4 @@ -use bevy::math::Vec4Swizzles; +use bevy::{color::palettes, math::Vec4Swizzles}; use bevy::{ecs::system::Resource, prelude::*}; use bevy_ecs_tilemap::prelude::*; mod helpers; @@ -360,7 +360,7 @@ fn highlight_tile_labels( if let Ok(label) = tile_label_q.get(tile_entity) { if let Ok(mut tile_text) = text_q.get_mut(label.0) { for section in tile_text.sections.iter_mut() { - section.style.color = Color::RED; + section.style.color = palettes::tailwind::RED_600.into(); } commands.entity(tile_entity).insert(HighlightedLabel); } diff --git a/src/render/chunk.rs b/src/render/chunk.rs index e8f86d1f..93319f58 100644 --- a/src/render/chunk.rs +++ b/src/render/chunk.rs @@ -1,9 +1,8 @@ use std::hash::{Hash, Hasher}; -use bevy::math::Mat4; -use bevy::prelude::{InheritedVisibility, Resource, Transform}; -use bevy::render::primitives::Aabb; use bevy::render::render_asset::RenderAssetUsages; +use bevy::render::{mesh::BaseMeshPipelineKey, primitives::Aabb}; +use bevy::{math::Mat4, render::mesh::PrimitiveTopology}; use bevy::{ math::{UVec2, UVec3, UVec4, Vec2, Vec3Swizzles, Vec4, Vec4Swizzles}, prelude::{Component, Entity, GlobalTransform, Mesh, Vec3}, @@ -14,6 +13,10 @@ use bevy::{ }, utils::HashMap, }; +use bevy::{ + prelude::{InheritedVisibility, Resource, Transform}, + render::mesh::MeshVertexBufferLayouts, +}; use crate::prelude::helpers::transform::{chunk_aabb, chunk_index_to_world_space}; use crate::render::extract::ExtractedFrustum; @@ -355,7 +358,11 @@ impl RenderChunk2d { } } - pub fn prepare(&mut self, device: &RenderDevice) { + pub fn prepare( + &mut self, + device: &RenderDevice, + mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts, + ) { if self.dirty_mesh { let size = ((self.size_in_tiles.x * self.size_in_tiles.y) * 4) as usize; let mut positions: Vec<[f32; 4]> = Vec::with_capacity(size); @@ -444,14 +451,18 @@ impl RenderChunk2d { } }); - let mesh_vertex_buffer_layout = self.mesh.get_mesh_vertex_buffer_layout(); + let mesh_vertex_buffer_layout = self + .mesh + .get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts); self.gpu_mesh = Some(GpuMesh { vertex_buffer, vertex_count: self.mesh.count_vertices() as u32, buffer_info, morph_targets: None, layout: mesh_vertex_buffer_layout, - primitive_topology: bevy::render::render_resource::PrimitiveTopology::TriangleList, + key_bits: BaseMeshPipelineKey::from_primitive_topology( + PrimitiveTopology::TriangleList, + ), }); self.dirty_mesh = false; } diff --git a/src/render/extract.rs b/src/render/extract.rs index 24166d47..06fd69a6 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -282,7 +282,7 @@ pub fn extract( visible: visible.0, position, texture, - color: color.0.as_linear_rgba_f32(), + color: color.0.to_linear().to_f32_array(), }; let data = tilemap_query.get(tilemap_id.0).unwrap(); diff --git a/src/render/material.rs b/src/render/material.rs index ada567c9..c2d14141 100644 --- a/src/render/material.rs +++ b/src/render/material.rs @@ -1,30 +1,33 @@ use bevy::{ core_pipeline::core_2d::Transparent2d, + math::FloatOrd, prelude::*, reflect::TypePath, render::{ extract_component::ExtractComponentPlugin, globals::GlobalsBuffer, render_asset::RenderAssets, - render_phase::{AddRenderCommand, DrawFunctions, RenderPhase}, + render_phase::{ + AddRenderCommand, DrawFunctions, PhaseItemExtraIndex, ViewSortedRenderPhases, + }, render_resource::{ AsBindGroup, AsBindGroupError, BindGroup, BindGroupEntry, BindGroupLayout, BindingResource, OwnedBindingResource, PipelineCache, RenderPipelineDescriptor, ShaderRef, SpecializedRenderPipeline, SpecializedRenderPipelines, }, renderer::RenderDevice, - texture::FallbackImage, + texture::{FallbackImage, GpuImage}, view::{ExtractedView, ViewUniforms, VisibleEntities}, Extract, Render, RenderApp, RenderSet, }, - utils::{FloatOrd, HashMap, HashSet}, + utils::{HashMap, HashSet}, }; use std::{hash::Hash, marker::PhantomData}; #[cfg(not(feature = "atlas"))] use bevy::render::renderer::RenderQueue; -use crate::prelude::TilemapId; +use crate::prelude::{TilemapId, TilemapRenderSettings}; use super::{ chunk::{ChunkId, RenderChunk2dStorage}, @@ -113,7 +116,7 @@ where } fn finish(&self, app: &mut App) { - if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { + if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_command::>() .init_resource::>() @@ -303,7 +306,7 @@ fn prepare_materials_tilemap( mut extracted_assets: ResMut>, mut render_materials: ResMut>, render_device: Res, - images: Res>, + images: Res>, fallback_image: Res, pipeline: Res>, ) { @@ -350,7 +353,7 @@ fn prepare_materials_tilemap( fn prepare_material_tilemap( material: &M, render_device: &RenderDevice, - images: &RenderAssets, + images: &RenderAssets, fallback_image: &FallbackImage, pipeline: &MaterialTilemapPipeline, ) -> Result, AsBindGroupError> { @@ -378,23 +381,20 @@ pub fn queue_material_tilemap_meshes( ), pipeline_cache: Res, view_uniforms: Res, - gpu_images: Res>, + gpu_images: Res>, msaa: Res, globals_buffer: Res, (standard_tilemap_meshes, materials): ( Query<(Entity, &ChunkId, &Transform, &TilemapId)>, Query<&Handle>, ), - mut views: Query<( - &ExtractedView, - &VisibleEntities, - &mut RenderPhase, - )>, + mut views: Query<(Entity, &ExtractedView, &VisibleEntities)>, render_materials: Res>, #[cfg(not(feature = "atlas"))] (mut texture_array_cache, render_queue): ( ResMut, Res, ), + mut transparent_render_phases: ResMut>, ) where M::Data: PartialEq + Eq + Hash + Clone, { @@ -409,7 +409,11 @@ pub fn queue_material_tilemap_meshes( return; } - for (view, visible_entities, mut transparent_phase) in views.iter_mut() { + for (view_entity, view, visible_entities) in views.iter_mut() { + let Some(transparent_phase) = transparent_render_phases.get_mut(&view_entity) else { + continue; + }; + let draw_tilemap = transparent_2d_draw_functions .read() .get_id::>() @@ -417,8 +421,7 @@ pub fn queue_material_tilemap_meshes( for (entity, chunk_id, transform, tilemap_id) in standard_tilemap_meshes.iter() { if !visible_entities - .entities - .iter() + .iter::>() .any(|&entity| entity.index() == tilemap_id.0.index()) { continue; @@ -475,7 +478,7 @@ pub fn queue_material_tilemap_meshes( pipeline: pipeline_id, sort_key: FloatOrd(z), batch_range: 0..1, - dynamic_offset: None, + extra_index: PhaseItemExtraIndex::NONE, }); } } @@ -489,7 +492,7 @@ pub fn bind_material_tilemap_meshes( render_device: Res, tilemap_pipeline: Res, view_uniforms: Res, - gpu_images: Res>, + gpu_images: Res>, globals_buffer: Res, mut image_bind_groups: ResMut, (standard_tilemap_meshes, materials): (Query<(&ChunkId, &TilemapId)>, Query<&Handle>), @@ -535,8 +538,7 @@ pub fn bind_material_tilemap_meshes( for (chunk_id, tilemap_id) in standard_tilemap_meshes.iter() { if !visible_entities - .entities - .iter() + .iter::>() .any(|&entity| entity.index() == tilemap_id.0.index()) { continue; diff --git a/src/render/mod.rs b/src/render/mod.rs index 4b41c3a0..f24e8c55 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -9,14 +9,20 @@ use bevy::{ render_phase::AddRenderCommand, render_resource::{FilterMode, SpecializedRenderPipelines, VertexFormat}, texture::ImageSamplerDescriptor, + view::{check_visibility, VisibilitySystems}, Render, RenderApp, RenderSet, }, }; #[cfg(not(feature = "atlas"))] use bevy::render::renderer::RenderDevice; +#[cfg(not(feature = "atlas"))] +use bevy::render::texture::GpuImage; -use crate::tiles::{TilePos, TileStorage}; +use crate::{ + prelude::TilemapRenderSettings, + tiles::{TilePos, TileStorage}, +}; use crate::{ prelude::TilemapTexture, render::{ @@ -110,10 +116,10 @@ impl Plugin for TilemapRenderingPlugin { app.add_plugins(MaterialTilemapPlugin::::default()); - app.world + app.world_mut() .resource_mut::>() .insert( - Handle::::default(), + Handle::::default().id(), StandardTilemapMaterial::default(), ); } @@ -209,9 +215,16 @@ impl Plugin for TilemapRenderingPlugin { Shader::from_wgsl ); + app.add_systems( + PostUpdate, + (check_visibility::>) + .in_set(VisibilitySystems::CheckVisibility) + .after(VisibilitySystems::CalculateBounds), + ); + let render_app = match app.get_sub_app_mut(RenderApp) { - Ok(render_app) => render_app, - Err(_) => return, + Some(render_app) => render_app, + None => return, }; render_app.init_resource::(); @@ -319,7 +332,7 @@ fn prepare_textures( render_device: Res, mut texture_array_cache: ResMut, extracted_tilemap_textures: Query<&ExtractedTilemapTexture>, - render_images: Res>, + render_images: Res>, ) { for extracted_texture in extracted_tilemap_textures.iter() { texture_array_cache.add_extracted_texture(extracted_texture); diff --git a/src/render/pipeline.rs b/src/render/pipeline.rs index facc8e07..09ec40bb 100644 --- a/src/render/pipeline.rs +++ b/src/render/pipeline.rs @@ -32,7 +32,6 @@ pub struct TilemapPipeline { impl FromWorld for TilemapPipeline { fn from_world(world: &mut World) -> Self { - let world = world.cell(); let render_device = world.get_resource::().unwrap(); let view_layout = render_device.create_bind_group_layout( diff --git a/src/render/prepare.rs b/src/render/prepare.rs index 24b307e8..afdb602f 100644 --- a/src/render/prepare.rs +++ b/src/render/prepare.rs @@ -9,8 +9,8 @@ use crate::render::extract::ExtractedFrustum; use crate::{ prelude::TilemapGridSize, render::RenderChunkSize, render::SecondsSinceStartup, FrustumCulling, }; -use bevy::log::trace; use bevy::prelude::{InheritedVisibility, Resource}; +use bevy::{log::trace, render::mesh::MeshVertexBufferLayouts}; use bevy::{ math::{Mat4, UVec4}, prelude::{Commands, Component, Entity, GlobalTransform, Query, Res, ResMut, Vec2}, @@ -63,6 +63,7 @@ pub(crate) fn prepare( render_device: Res, render_queue: Res, seconds_since_startup: Res, + mut mesh_vertex_buffer_layouts: ResMut, ) { for tile in extracted_tiles.iter() { // First if the tile position has changed remove the tile from the old location. @@ -188,7 +189,7 @@ pub(crate) fn prepare( } trace!("Preparing chunk: {:?}", chunk.get_index()); - chunk.prepare(&render_device); + chunk.prepare(&render_device, &mut mesh_vertex_buffer_layouts); let mut chunk_uniform: TilemapUniformData = chunk.into(); chunk_uniform.time = **seconds_since_startup; diff --git a/src/render/shaders/tilemap_vertex.wgsl b/src/render/shaders/tilemap_vertex.wgsl index d4eb3c09..3771fc88 100644 --- a/src/render/shaders/tilemap_vertex.wgsl +++ b/src/render/shaders/tilemap_vertex.wgsl @@ -130,7 +130,7 @@ fn vertex(vertex_input: VertexInput) -> MeshVertexOutput { out.uv = atlas_uvs[vertex_input.v_index % 4u]; out.tile_id = i32(texture_index); // out.uv = out.uv + 1e-5; - out.position = view.view_proj * mesh_data.world_position; + out.position = view.clip_from_world * mesh_data.world_position; out.color = vertex_input.color; out.storage_position = vec2(vertex_input.position.xy); return out; diff --git a/src/render/texture_array_cache.rs b/src/render/texture_array_cache.rs index 270a7385..aaabd1d4 100644 --- a/src/render/texture_array_cache.rs +++ b/src/render/texture_array_cache.rs @@ -3,7 +3,7 @@ use crate::{TilemapSpacing, TilemapTexture, TilemapTextureSize, TilemapTileSize} use bevy::asset::Assets; use bevy::prelude::Resource; use bevy::{ - prelude::{Image, Res}, + prelude::{Image, Res, UVec2}, render::{ render_asset::RenderAssets, render_resource::{ @@ -137,7 +137,7 @@ impl TextureArrayCache { pub fn prepare( &mut self, render_device: &RenderDevice, - render_images: &Res>, + render_images: &Res>, ) { let prepare_queue = self.prepare_queue.drain().collect::>(); for texture in prepare_queue.iter() { @@ -205,7 +205,10 @@ impl TextureArrayCache { texture: gpu_texture, sampler, texture_view, - size: tile_size.into(), + size: UVec2 { + x: tile_size.x as u32, + y: tile_size.y as u32, + }, mip_level_count, }; @@ -228,7 +231,7 @@ impl TextureArrayCache { &mut self, render_device: &RenderDevice, render_queue: &RenderQueue, - render_images: &Res>, + render_images: &Res>, ) { let queue_queue = self.queue_queue.drain().collect::>();