From 0e71c8af09ae303916200fd5fdc1d36c9dc1a64a Mon Sep 17 00:00:00 2001 From: Brian Merchant Date: Fri, 30 Sep 2022 13:06:06 -0700 Subject: [PATCH 1/4] Preparing changing TilemapTexture to an enum; making sure atlas mode still works. --- examples/accessing_tiles.rs | 2 +- examples/animation.rs | 4 +- examples/basic.rs | 12 ++--- examples/bench.rs | 2 +- examples/chunking.rs | 2 +- examples/colors.rs | 2 +- examples/frustum_cull_test.rs | 12 ++--- examples/game_of_life.rs | 2 +- examples/helpers/tiled.rs | 2 +- examples/hexagon_column.rs | 2 +- examples/hexagon_generation.rs | 6 +-- examples/hexagon_row.rs | 2 +- examples/iso_diamond.rs | 2 +- examples/iso_staggered.rs | 2 +- examples/layers.rs | 4 +- examples/ldtk/ldtk.rs | 2 +- examples/mouse_to_tile.rs | 12 ++--- examples/move_tile.rs | 2 +- examples/neighbors.rs | 6 +-- examples/random_map.rs | 2 +- examples/remove_tiles.rs | 2 +- examples/visibility.rs | 2 +- src/array_texture_preload.rs | 42 ++++++++--------- src/map/mod.rs | 86 ++++++++++++++++++++++++++++++++-- src/render/draw.rs | 15 +++--- src/render/extract.rs | 2 +- src/render/mod.rs | 22 +++------ src/render/prepare.rs | 2 +- src/render/queue.rs | 11 +++-- 29 files changed, 168 insertions(+), 98 deletions(-) diff --git a/examples/accessing_tiles.rs b/examples/accessing_tiles.rs index 6f2dac7c..5c4ea53b 100644 --- a/examples/accessing_tiles.rs +++ b/examples/accessing_tiles.rs @@ -88,7 +88,7 @@ fn startup(mut commands: Commands, asset_server: Res) { size: tilemap_size, storage: tile_storage, map_type: tilemap_type, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/examples/animation.rs b/examples/animation.rs index 8128f588..938fa78e 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -59,7 +59,7 @@ fn create_background(mut commands: Commands, asset_server: Res) { grid_size, tile_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), transform: get_tilemap_center_transform(&size, &grid_size, 0.0), ..Default::default() }); @@ -114,7 +114,7 @@ fn create_animated_flowers(mut commands: Commands, asset_server: Res, ) { if keyboard_input.just_pressed(KeyCode::Space) { - let texture_handle_a: Handle = asset_server.load("tiles.png"); - let texture_handle_b: Handle = asset_server.load("tiles2.png"); + let texture_a = TilemapTexture::Single(asset_server.load("tiles.png")); + let texture_b = TilemapTexture::Single(asset_server.load("tiles2.png")); for (mut tilemap_tex, _) in &mut query { - if tilemap_tex.0 == texture_handle_a { - tilemap_tex.0 = texture_handle_b.clone(); + if *tilemap_tex == texture_a { + *tilemap_tex = texture_b.clone(); } else { - tilemap_tex.0 = texture_handle_a.clone(); + *tilemap_tex = texture_a.clone(); } } } diff --git a/examples/bench.rs b/examples/bench.rs index a2f5a0c7..f530fb1d 100644 --- a/examples/bench.rs +++ b/examples/bench.rs @@ -33,7 +33,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/examples/chunking.rs b/examples/chunking.rs index 8968f247..242d4c9b 100644 --- a/examples/chunking.rs +++ b/examples/chunking.rs @@ -45,7 +45,7 @@ fn spawn_chunk(commands: &mut Commands, asset_server: &AssetServer, chunk_pos: I grid_size: TILE_SIZE.into(), size: CHUNK_SIZE.into(), storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size: TILE_SIZE, transform, ..Default::default() diff --git a/examples/colors.rs b/examples/colors.rs index 88fa837a..6b3bec32 100644 --- a/examples/colors.rs +++ b/examples/colors.rs @@ -83,7 +83,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: total_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, map_type: TilemapType::Square { diagonal_neighbors: false, diff --git a/examples/frustum_cull_test.rs b/examples/frustum_cull_test.rs index 71396b72..b06aa1e0 100644 --- a/examples/frustum_cull_test.rs +++ b/examples/frustum_cull_test.rs @@ -85,7 +85,7 @@ fn spawn_tilemap(mut commands: Commands, tile_handle_square: Res { *map_type = TilemapType::Hexagon(HexCoordSystem::Row); - *map_texture = TilemapTexture((*tile_handle_hex_row).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_row).clone()); *tile_size = TILE_SIZE_HEX_ROW; *grid_size = GRID_SIZE_HEX_ROW; } @@ -198,7 +198,7 @@ fn swap_map_type( } TilemapType::Hexagon(HexCoordSystem::RowOdd) => { *map_type = TilemapType::Hexagon(HexCoordSystem::Column); - *map_texture = TilemapTexture((*tile_handle_hex_col).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_col).clone()); *tile_size = TILE_SIZE_HEX_COL; *grid_size = GRID_SIZE_HEX_COL; } @@ -212,7 +212,7 @@ fn swap_map_type( *map_type = TilemapType::Square { diagonal_neighbors: false, }; - *map_texture = TilemapTexture((*tile_handle_square).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_square).clone()); *tile_size = TILE_SIZE_SQUARE; *grid_size = GRID_SIZE_SQUARE; } diff --git a/examples/game_of_life.rs b/examples/game_of_life.rs index 3bb88811..043c3344 100644 --- a/examples/game_of_life.rs +++ b/examples/game_of_life.rs @@ -39,7 +39,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), map_type: TilemapType::Square { diff --git a/examples/helpers/tiled.rs b/examples/helpers/tiled.rs index 097cfa2a..4c138c94 100644 --- a/examples/helpers/tiled.rs +++ b/examples/helpers/tiled.rs @@ -230,7 +230,7 @@ pub fn process_loaded_maps( grid_size, size: map_size, storage: tile_storage, - texture: TilemapTexture( + texture: TilemapTexture::Single( tiled_map .tilesets .get(&tileset.first_gid) diff --git a/examples/hexagon_column.rs b/examples/hexagon_column.rs index 3eacaf6e..c9b44324 100644 --- a/examples/hexagon_column.rs +++ b/examples/hexagon_column.rs @@ -79,7 +79,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: total_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, map_type: TilemapType::Hexagon(HexCoordSystem::Column), ..Default::default() diff --git a/examples/hexagon_generation.rs b/examples/hexagon_generation.rs index 24d4146e..efad5d12 100644 --- a/examples/hexagon_generation.rs +++ b/examples/hexagon_generation.rs @@ -76,7 +76,7 @@ fn spawn_tilemap(mut commands: Commands, tile_handle_hex_row: Res) { grid_size, size: total_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, map_type: TilemapType::Hexagon(HexCoordSystem::Row), ..Default::default() diff --git a/examples/iso_diamond.rs b/examples/iso_diamond.rs index ff826959..90da3d7a 100644 --- a/examples/iso_diamond.rs +++ b/examples/iso_diamond.rs @@ -79,7 +79,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: total_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, map_type: TilemapType::isometric_diamond(false), ..Default::default() diff --git a/examples/iso_staggered.rs b/examples/iso_staggered.rs index 0066a8fe..1d9e8a8e 100644 --- a/examples/iso_staggered.rs +++ b/examples/iso_staggered.rs @@ -81,7 +81,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: total_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, map_type: TilemapType::isometric_staggered(false), ..Default::default() diff --git a/examples/layers.rs b/examples/layers.rs index 98a62323..664a2c0d 100644 --- a/examples/layers.rs +++ b/examples/layers.rs @@ -30,7 +30,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle.clone()), + texture: TilemapTexture::Single(texture_handle.clone()), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() @@ -54,7 +54,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size: grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size: TilemapTileSize { x: 16.0, y: 16.0 }, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 1.0) * Transform::from_xyz(32.0, 32.0, 0.0), diff --git a/examples/ldtk/ldtk.rs b/examples/ldtk/ldtk.rs index 10180307..20bb7dc7 100644 --- a/examples/ldtk/ldtk.rs +++ b/examples/ldtk/ldtk.rs @@ -207,7 +207,7 @@ pub fn process_loaded_tile_maps( grid_size, size, storage, - texture: TilemapTexture(texture), + texture: TilemapTexture::Single(texture), tile_size, transform: get_tilemap_center_transform( &size, diff --git a/examples/mouse_to_tile.rs b/examples/mouse_to_tile.rs index 6ead424f..9fe9cf9c 100644 --- a/examples/mouse_to_tile.rs +++ b/examples/mouse_to_tile.rs @@ -81,7 +81,7 @@ fn spawn_tilemap(mut commands: Commands, tile_handle_square: Res { *map_type = TilemapType::Hexagon(HexCoordSystem::Row); - *map_texture = TilemapTexture((*tile_handle_hex_row).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_row).clone()); *tile_size = TILE_SIZE_HEX_ROW; *grid_size = GRID_SIZE_HEX_ROW; } @@ -233,7 +233,7 @@ fn swap_map_type( } TilemapType::Hexagon(HexCoordSystem::RowOdd) => { *map_type = TilemapType::Hexagon(HexCoordSystem::Column); - *map_texture = TilemapTexture((*tile_handle_hex_col).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_col).clone()); *tile_size = TILE_SIZE_HEX_COL; *grid_size = GRID_SIZE_HEX_COL; } @@ -247,7 +247,7 @@ fn swap_map_type( *map_type = TilemapType::Square { diagonal_neighbors: false, }; - *map_texture = TilemapTexture((*tile_handle_square).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_square).clone()); *tile_size = TILE_SIZE_SQUARE; *grid_size = GRID_SIZE_SQUARE; } diff --git a/examples/move_tile.rs b/examples/move_tile.rs index 528cdbd9..7a2610c0 100644 --- a/examples/move_tile.rs +++ b/examples/move_tile.rs @@ -36,7 +36,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/examples/neighbors.rs b/examples/neighbors.rs index 1cd5146e..a9832e13 100644 --- a/examples/neighbors.rs +++ b/examples/neighbors.rs @@ -73,7 +73,7 @@ fn spawn_tilemap(mut commands: Commands, tile_handle_hex_row: Res { *map_type = TilemapType::Hexagon(HexCoordSystem::Column); - *map_texture = TilemapTexture((*tile_handle_hex_col).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_col).clone()); *tile_size = TILE_SIZE_HEX_COL; *grid_size = GRID_SIZE_HEX_COL; } @@ -203,7 +203,7 @@ fn swap_map_type( } TilemapType::Hexagon(HexCoordSystem::ColumnOdd) => { *map_type = TilemapType::Hexagon(HexCoordSystem::Row); - *map_texture = TilemapTexture((*tile_handle_hex_row).clone()); + *map_texture = TilemapTexture::Single((*tile_handle_hex_row).clone()); *tile_size = TILE_SIZE_HEX_ROW; *grid_size = GRID_SIZE_HEX_ROW; } diff --git a/examples/random_map.rs b/examples/random_map.rs index a137ec3a..2dac52a1 100644 --- a/examples/random_map.rs +++ b/examples/random_map.rs @@ -42,7 +42,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/examples/remove_tiles.rs b/examples/remove_tiles.rs index 76896aba..7cecea5c 100644 --- a/examples/remove_tiles.rs +++ b/examples/remove_tiles.rs @@ -37,7 +37,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/examples/visibility.rs b/examples/visibility.rs index 25d0604d..ecbd25cf 100644 --- a/examples/visibility.rs +++ b/examples/visibility.rs @@ -37,7 +37,7 @@ fn startup(mut commands: Commands, asset_server: Res) { grid_size, size: tilemap_size, storage: tile_storage, - texture: TilemapTexture(texture_handle), + texture: TilemapTexture::Single(texture_handle), tile_size, transform: get_tilemap_center_transform(&tilemap_size, &grid_size, 0.0), ..Default::default() diff --git a/src/array_texture_preload.rs b/src/array_texture_preload.rs index 477fda29..961c996e 100644 --- a/src/array_texture_preload.rs +++ b/src/array_texture_preload.rs @@ -1,18 +1,17 @@ -use std::sync::{Arc, RwLock}; - -use bevy::{ - prelude::{Assets, Handle, Image, Res, ResMut}, - render::{render_resource::FilterMode, texture::ImageSettings, Extract}, -}; - use crate::{ prelude::{TilemapSpacing, TilemapTileSize}, render::TextureArrayCache, + TilemapTexture, }; +use bevy::{ + prelude::{Assets, Image, Res, ResMut}, + render::{render_resource::FilterMode, texture::ImageSettings, Extract}, +}; +use std::sync::{Arc, RwLock}; #[derive(Default, Debug, Clone)] pub struct TilemapArrayTexture { - pub atlas_texture: Handle, + pub texture: TilemapTexture, pub tile_size: TilemapTileSize, pub tile_spacing: TilemapSpacing, /// Defaults to ImageSettings. @@ -48,22 +47,23 @@ pub(crate) fn extract( array_texture_loader: Extract>, mut texture_array_cache: ResMut, ) { - for texture in array_texture_loader.drain() { - if let Some(image) = images.get(&texture.atlas_texture) { - texture_array_cache.add( - &texture.atlas_texture, - texture.tile_size.into(), - image.size(), - texture.tile_spacing.into(), - if let Some(filter) = texture.filter { - filter - } else { - default_image_settings.default_sampler.mag_filter - }, + for mut array_texture in array_texture_loader.drain() { + if array_texture.filter.is_none() { + array_texture + .filter + .replace(default_image_settings.default_sampler.mag_filter); + } + if array_texture.texture.verify_ready(&images) { + texture_array_cache.add_texture( + array_texture.texture, + array_texture.tile_size, + array_texture.tile_spacing, + default_image_settings.default_sampler.min_filter, + &images, ); } else { // Image hasn't loaded yet punt to next frame. - array_texture_loader.add(texture); + array_texture_loader.add(array_texture); } } } diff --git a/src/map/mod.rs b/src/map/mod.rs index b3c9b200..fe0d43bd 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -1,3 +1,6 @@ +use bevy::asset::Assets; +use bevy::prelude::{Res, ResMut}; +use bevy::render::render_resource::TextureUsages; use bevy::{ math::{UVec2, Vec2}, prelude::{Component, Entity, Handle, Image}, @@ -70,9 +73,86 @@ impl From for TilemapSize { } } -/// A bevy asset handle linking to the tilemap atlas image file. -#[derive(Component, Clone, Default, Debug, Hash)] -pub struct TilemapTexture(pub Handle); +#[derive(Component, Clone, Debug, Hash, PartialEq, Eq)] +pub enum TilemapTexture { + /// All textures for tiles are inside a single image asset. + Single(Handle), + /// Each tile's texture has its own image asset (each asset must have the same size), so there + /// is a vector of image assets. + /// + /// Each image should have the same size, identical to the provided `TilemapTileSize`. If this + /// is not the case, a panic will be thrown during the verification when images are being + /// extracted to the render world. + /// + /// This only makes sense to use when the `"atlas"` feature is NOT enabled, as texture arrays + /// are required to handle storing an array of textures. Therefore, this variant is only + /// available when `"atlas"` is not enabled. + #[cfg(not(feature = "atlas"))] + Vector(Vec>), +} + +impl Default for TilemapTexture { + fn default() -> Self { + TilemapTexture::Single(Default::default()) + } +} + +impl TilemapTexture { + #[cfg(feature = "atlas")] + pub fn image_handle(&self) -> &Handle { + match &self { + TilemapTexture::Single(handle) => handle, + } + } + + pub fn image_handles(&self) -> Vec<&Handle> { + match &self { + TilemapTexture::Single(handle) => vec![handle], + #[cfg(not(feature = "atlas"))] + TilemapTexture::Vector(handles) => handles.iter().collect(), + } + } + + pub fn verify_ready(&self, images: &Res>) -> bool { + self.image_handles().into_iter().all(|h| { + if let Some(image) = images.get(h) { + image + .texture_descriptor + .usage + .contains(TextureUsages::COPY_SRC) + } else { + false + } + }) + } + + /// Sets images with the `COPY_SRC` flag. + pub fn set_images_to_copy_src(&self, images: &mut ResMut>) { + for handle in self.image_handles() { + if let Some(mut image) = images.get_mut(handle) { + if !image + .texture_descriptor + .usage + .contains(TextureUsages::COPY_SRC) + { + image.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING + | TextureUsages::COPY_SRC + | TextureUsages::COPY_DST; + } + } + } + } + + pub fn clone_weak(&self) -> Self { + match self { + TilemapTexture::Single(handle) => TilemapTexture::Single(handle.clone_weak()), + #[cfg(not(feature = "atlas"))] + TilemapTexture::Vector(handles) => { + TilemapTexture::Vector(handles.iter().map(|h| h.clone_weak()).collect()) + } + } + } +} /// Size of the tiles in pixels #[derive(Component, Default, Clone, Copy, Debug, PartialOrd, PartialEq)] diff --git a/src/render/draw.rs b/src/render/draw.rs index 49e20853..ec171c40 100644 --- a/src/render/draw.rs +++ b/src/render/draw.rs @@ -5,7 +5,7 @@ use bevy::{ SystemParamItem, }, math::UVec4, - prelude::{Entity, Handle, Image}, + prelude::Entity, render::{ mesh::GpuBufferInfo, render_phase::{RenderCommand, RenderCommandResult, TrackedRenderPass}, @@ -15,6 +15,7 @@ use bevy::{ }; use crate::map::TilemapId; +use crate::TilemapTexture; use super::{ chunk::{ChunkId, RenderChunk2dStorage, TilemapUniformData}, @@ -92,20 +93,16 @@ impl RenderCommand for SetTilemapBindGroup { pub struct SetMaterialBindGroup; impl RenderCommand for SetMaterialBindGroup { - type Param = (SRes, SQuery>>); + type Param = (SRes, SQuery>); #[inline] fn render<'w>( _view: Entity, item: &Transparent2d, - (image_bind_groups, entities_with_images): SystemParamItem<'w, '_, Self::Param>, + (image_bind_groups, entities_with_textures): SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - let image_handle = entities_with_images.get(item.entity).unwrap(); - let bind_group = image_bind_groups - .into_inner() - .values - .get(image_handle) - .unwrap(); + let texture = entities_with_textures.get(item.entity).unwrap(); + let bind_group = image_bind_groups.into_inner().values.get(texture).unwrap(); pass.set_bind_group(I, bind_group, &[]); RenderCommandResult::Success diff --git a/src/render/extract.rs b/src/render/extract.rs index fc9a6d97..5b96915f 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -262,7 +262,7 @@ pub fn extract( // Extracts tilemap textures. for (entity, _, tile_size, spacing, _, _, texture, _, _, _) in tilemap_query.iter() { - let texture_size = if let Some(_atlas_image) = images.get(&texture.0) { + let texture_size = if let Some(_atlas_image) = images.get(texture.image_handle()) { #[cfg(not(feature = "atlas"))] if !_atlas_image .texture_descriptor diff --git a/src/render/mod.rs b/src/render/mod.rs index 1fe48af0..2de8c5eb 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -9,8 +9,7 @@ use bevy::{ mesh::MeshVertexAttribute, render_phase::AddRenderCommand, render_resource::{ - DynamicUniformBuffer, FilterMode, SpecializedRenderPipelines, TextureUsages, - VertexFormat, + DynamicUniformBuffer, FilterMode, SpecializedRenderPipelines, VertexFormat, }, RenderApp, RenderStage, }, @@ -242,20 +241,13 @@ impl Plugin for TilemapRenderingPlugin { } } -pub fn set_texture_to_copy_src(mut textures: ResMut>, query: Query<&TilemapTexture>) { +pub fn set_texture_to_copy_src( + mut images: ResMut>, + texture_query: Query<&TilemapTexture>, +) { // quick and dirty, run this for all textures anytime a texture component is created. - for texture in query.iter() { - if let Some(mut texture) = textures.get_mut(&texture.0) { - if !texture - .texture_descriptor - .usage - .contains(TextureUsages::COPY_SRC) - { - texture.texture_descriptor.usage = TextureUsages::TEXTURE_BINDING - | TextureUsages::COPY_SRC - | TextureUsages::COPY_DST; - } - } + for texture in texture_query.iter() { + texture.set_images_to_copy_src(&mut images) } } diff --git a/src/render/prepare.rs b/src/render/prepare.rs index c93b3337..47860345 100644 --- a/src/render/prepare.rs +++ b/src/render/prepare.rs @@ -183,7 +183,7 @@ pub(crate) fn prepare( commands .spawn() - .insert(chunk.texture.0.clone_weak()) + .insert(chunk.texture.clone_weak()) .insert(chunk.get_transform()) .insert(ChunkId(chunk.get_index())) .insert(chunk.get_map_type()) diff --git a/src/render/queue.rs b/src/render/queue.rs index 5307ad94..8d1f3a58 100644 --- a/src/render/queue.rs +++ b/src/render/queue.rs @@ -1,7 +1,7 @@ use bevy::{ core_pipeline::core_2d::Transparent2d, math::UVec4, - prelude::{Commands, Component, Entity, Handle, Image, Msaa, Query, Res, ResMut, Transform}, + prelude::{Commands, Component, Entity, Image, Msaa, Query, Res, ResMut, Transform}, render::{ render_asset::RenderAssets, render_phase::{DrawFunctions, RenderPhase}, @@ -18,6 +18,7 @@ use bevy::{ use crate::map::TilemapId; +use crate::TilemapTexture; #[cfg(not(feature = "atlas"))] use bevy::render::renderer::RenderQueue; @@ -86,7 +87,7 @@ pub struct TilemapViewBindGroup { #[derive(Default)] pub struct ImageBindGroups { - pub values: HashMap, BindGroup>, + pub values: HashMap, } #[allow(clippy::too_many_arguments)] @@ -156,18 +157,18 @@ pub fn queue_meshes( } #[cfg(feature = "atlas")] - if gpu_images.get(&chunk.texture.0).is_none() { + if gpu_images.get(chunk.texture.image_handle()).is_none() { continue; } image_bind_groups .values - .entry(chunk.texture.0.clone_weak()) + .entry(chunk.texture.clone_weak()) .or_insert_with(|| { #[cfg(not(feature = "atlas"))] let gpu_image = texture_array_cache.get(&chunk.texture.0); #[cfg(feature = "atlas")] - let gpu_image = gpu_images.get(&chunk.texture.0).unwrap(); + let gpu_image = gpu_images.get(chunk.texture.image_handle()).unwrap(); render_device.create_bind_group(&BindGroupDescriptor { entries: &[ BindGroupEntry { From 91fdf6fdfef40f1ca22b2f2ab745b9568f61744f Mon Sep 17 00:00:00 2001 From: Brian Merchant Date: Fri, 30 Sep 2022 13:26:51 -0700 Subject: [PATCH 2/4] Changing how works; confirming that atlas mode still works. --- src/map/mod.rs | 20 ++++++++ src/render/extract.rs | 112 +++++++++++++++++++++++++++++------------- src/render/mod.rs | 2 +- 3 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/map/mod.rs b/src/map/mod.rs index fe0d43bd..47cdcbdb 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -114,6 +114,12 @@ impl TilemapTexture { } pub fn verify_ready(&self, images: &Res>) -> bool { + #[cfg(feature = "atlas")] + { + images.get(self.image_handle()).is_some() + } + + #[cfg(not(feature = "atlas"))] self.image_handles().into_iter().all(|h| { if let Some(image) = images.get(h) { image @@ -182,6 +188,13 @@ impl From<&TilemapTileSize> for Vec2 { } } +impl From for TilemapTileSize { + fn from(v: Vec2) -> Self { + let Vec2 { x, y } = v; + TilemapTileSize { x, y } + } +} + /// Size of the tiles on the grid in pixels. /// This can be used to overlay tiles on top of each other. /// Ex. A 16x16 pixel tile can be overlapped by 8 pixels by using @@ -257,6 +270,13 @@ impl From for TilemapTextureSize { } } +impl From for TilemapTextureSize { + fn from(tile_size: TilemapTileSize) -> Self { + let TilemapTileSize { x, y } = tile_size; + TilemapTextureSize { x, y } + } +} + /// Different hex_grid coordinate systems. You can find out more at this link: #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum HexCoordSystem { diff --git a/src/render/extract.rs b/src/render/extract.rs index 5b96915f..44b92a2b 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -61,11 +61,11 @@ pub struct ExtractedRemovedMapBundle { #[derive(Bundle)] pub struct ExtractedTilemapBundle { transform: GlobalTransform, - size: TilemapTileSize, + tile_size: TilemapTileSize, grid_size: TilemapGridSize, texture_size: TilemapTextureSize, spacing: TilemapSpacing, - mesh_type: TilemapType, + map_type: TilemapType, texture: TilemapTexture, map_size: TilemapSize, visibility: ComputedVisibility, @@ -77,11 +77,66 @@ pub(crate) struct ExtractedTilemapTexture { pub tilemap_id: TilemapId, pub tile_size: TilemapTileSize, pub texture_size: TilemapTextureSize, - pub spacing: TilemapSpacing, + pub tile_spacing: TilemapSpacing, + pub tile_count: u32, pub texture: TilemapTexture, pub filtering: FilterMode, } +impl ExtractedTilemapTexture { + pub fn new( + tilemap_entity: Entity, + texture: TilemapTexture, + tile_size: TilemapTileSize, + tile_spacing: TilemapSpacing, + filtering: FilterMode, + image_assets: &Res>, + ) -> ExtractedTilemapTexture { + let (tile_count, texture_size) = match &texture { + TilemapTexture::Single(handle) => { + let image = image_assets.get(handle).expect( + "Expected image to have finished loading if \ + it is being extracted as a texture!", + ); + let texture_size: TilemapTextureSize = image.size().into(); + let tile_count_x = + (texture_size.x + tile_spacing.x) / (tile_size.x + tile_spacing.x); + let tile_count_y = + (texture_size.y + tile_spacing.y) / (tile_size.y + tile_spacing.y); + ((tile_count_x * tile_count_y) as u32, texture_size) + } + #[cfg(not(feature = "atlas"))] + TilemapTexture::Vector(handles) => { + for handle in handles { + let image = image_assets.get(handle).expect( + "Expected image to have finished loading if \ + it is being extracted as a texture!", + ); + let this_tile_size: TilemapTileSize = image.size().into(); + if this_tile_size != tile_size { + panic!( + "Expected all provided image assets to have size {:?}, \ + but found image with size: {:?}", + tile_size, this_tile_size + ); + } + } + (handles.len() as u32, tile_size.into()) + } + }; + + ExtractedTilemapTexture { + tilemap_id: TilemapId(tilemap_entity), + texture: texture.clone(), + tile_size, + tile_spacing, + filtering, + tile_count, + texture_size, + } + } +} + #[derive(Bundle)] pub(crate) struct ExtractedTilemapTextureBundle { data: ExtractedTilemapTexture, @@ -207,11 +262,11 @@ pub fn extract( data.0, ExtractedTilemapBundle { transform: *data.1, - size: *data.2, + tile_size: *data.2, texture_size: TilemapTextureSize::default(), spacing: *data.3, grid_size: *data.4, - mesh_type: *data.5, + map_type: *data.5, texture: data.6.clone(), map_size: *data.7, visibility: data.8.clone(), @@ -242,11 +297,11 @@ pub fn extract( data.0, ExtractedTilemapBundle { transform: *data.1, - size: *data.2, + tile_size: *data.2, texture_size: TilemapTextureSize::default(), spacing: *data.3, grid_size: *data.4, - mesh_type: *data.5, + map_type: *data.5, texture: data.6.clone(), map_size: *data.7, visibility: data.8.clone(), @@ -261,35 +316,22 @@ pub fn extract( extracted_tilemaps.drain().map(|kv| kv.1).collect(); // Extracts tilemap textures. - for (entity, _, tile_size, spacing, _, _, texture, _, _, _) in tilemap_query.iter() { - let texture_size = if let Some(_atlas_image) = images.get(texture.image_handle()) { - #[cfg(not(feature = "atlas"))] - if !_atlas_image - .texture_descriptor - .usage - .contains(TextureUsages::COPY_SRC) - { - continue; - } - - _atlas_image.size().into() - } else { - continue; - }; - - extracted_tilemap_textures.push(( - entity, - ExtractedTilemapTextureBundle { - data: ExtractedTilemapTexture { - tilemap_id: TilemapId(entity), - tile_size: *tile_size, - texture_size, - spacing: *spacing, - texture: texture.clone(), - filtering: default_image_settings.default_sampler.min_filter, + for (entity, _, tile_size, tile_spacing, _, _, texture, _, _, _) in tilemap_query.iter() { + if texture.verify_ready(&images) { + extracted_tilemap_textures.push(( + entity, + ExtractedTilemapTextureBundle { + data: ExtractedTilemapTexture::new( + entity, + texture.clone(), + *tile_size, + *tile_spacing, + default_image_settings.default_sampler.min_filter, + &images, + ), }, - }, - )); + )) + } } for (entity, frustum) in camera_query.iter() { diff --git a/src/render/mod.rs b/src/render/mod.rs index 2de8c5eb..d802a46b 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -313,7 +313,7 @@ fn prepare_textures( for tilemap in extracted_tilemaps.iter() { let tile_size: Vec2 = tilemap.tile_size.into(); let texture_size: Vec2 = tilemap.texture_size.into(); - let spacing: Vec2 = tilemap.spacing.into(); + let spacing: Vec2 = tilemap.tile_spacing.into(); texture_array_cache.add( &tilemap.texture.0, tile_size, From 4dea4c0de42d22cf0264de00640b7c24e26df773 Mon Sep 17 00:00:00 2001 From: Brian Merchant Date: Fri, 30 Sep 2022 13:49:32 -0700 Subject: [PATCH 3/4] Added in TilemapTexture::Vector functionality; ensured atlas feature is still working. --- assets/hex-tile-0.png | Bin 0 -> 825 bytes assets/hex-tile-1.png | Bin 0 -> 2256 bytes assets/hex-tile-2.png | Bin 0 -> 2557 bytes examples/basic.rs | 2 +- examples/texture_vec.rs | 97 ++++++++++ src/lib.rs | 2 + src/map/mod.rs | 2 +- src/render/extract.rs | 3 - src/render/mod.rs | 15 +- src/render/queue.rs | 4 +- src/render/texture_array_cache.rs | 303 ++++++++++++++++++++---------- 11 files changed, 312 insertions(+), 116 deletions(-) create mode 100644 assets/hex-tile-0.png create mode 100644 assets/hex-tile-1.png create mode 100644 assets/hex-tile-2.png create mode 100644 examples/texture_vec.rs diff --git a/assets/hex-tile-0.png b/assets/hex-tile-0.png new file mode 100644 index 0000000000000000000000000000000000000000..a5aced780233b3475543f32736cce8ac337fa3a2 GIT binary patch literal 825 zcmV-91IGM`P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10>(*1 zK~!jg?V3MK8etfRpEH1Po5T=0)J?<0KqnGs>7XMcj>O51jMvUAba3d13r!ajO{^1x z-B=COfrN(8#U|H~5bK3MZwI;da#Do~e!b?N@DliJ zf4)p6BaKGm$%DJ8*Xy#iwdI^v4Im@GbE5$V_6Zvs8**}TqB{2-j*pLJeSO_2axl)$ z9w3oOM2f|tSeB(a>mRW!ONzy!L?RJeVh`W~kV>VZI^Wb(DivGcLL2{S0yj4|EH5wP z1uV-V91a5vG;U3PEeNlmX&L}aigP>~UqCg!fNFdJ)%XIc@dZ@l3#i5yP>nC38ec#) zzJO|$xGhv*S(f4`)8oiGSOP8qj*gC$1)3E{)=T&gwidm;xhr1ZUKj5aI85#HU0eraCIO3t|tDN00000NkvXXu0mjf DKf_~P literal 0 HcmV?d00001 diff --git a/assets/hex-tile-1.png b/assets/hex-tile-1.png new file mode 100644 index 0000000000000000000000000000000000000000..e800c63d6131b739030ccd81db3e0c37534d47c8 GIT binary patch literal 2256 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 { + commands.spawn_bundle(Camera2dBundle::default()); + + let image_handles = vec![ + asset_server.load("hex-tile-0.png"), + asset_server.load("hex-tile-1.png"), + asset_server.load("hex-tile-2.png"), + ]; + let texture_vec = TilemapTexture::Vector(image_handles); + + let map_size = TilemapSize { + x: MAP_DIAMETER, + y: MAP_DIAMETER, + }; + + let mut tile_storage = TileStorage::empty(map_size); + let tilemap_entity = commands.spawn().id(); + let tilemap_id = TilemapId(tilemap_entity); + + let tile_positions = generate_hexagon( + AxialPos::from_tile_pos_given_coord_system(&MAP_CENTER, COORD_SYS), + MAP_RADIUS, + ) + .into_iter() + .map(|axial_pos| axial_pos.as_tile_pos_given_coord_system(COORD_SYS)); + + let mut rng = thread_rng(); + let weighted_tile_choices = [ + (TileTexture(0), 0.8), + (TileTexture(1), 0.1), + (TileTexture(2), 0.1), + ]; + for position in tile_positions { + let texture = weighted_tile_choices + .choose_weighted(&mut rng, |choice| choice.1) + .unwrap() + .0; + let tile_entity = commands + .spawn() + .insert_bundle(TileBundle { + position, + tilemap_id, + texture, + ..Default::default() + }) + .id(); + tile_storage.set(&position, tile_entity); + } + + let tile_size = TILE_SIZE; + let grid_size = TILE_SIZE.into(); + + commands + .entity(tilemap_entity) + .insert_bundle(TilemapBundle { + grid_size, + tile_size, + size: map_size, + storage: tile_storage, + texture: texture_vec, + map_type: TilemapType::Hexagon(COORD_SYS), + transform: get_tilemap_center_transform(&map_size, &grid_size, 0.0), + ..Default::default() + }); +} + +fn main() { + App::new() + .insert_resource(WindowDescriptor { + width: 1270.0, + height: 720.0, + title: String::from("Using TilemapTexture::Vector instead of TilemapTexture::Single"), + ..Default::default() + }) + .insert_resource(ImageSettings::default_nearest()) + .add_plugins(DefaultPlugins) + .add_plugin(TilemapPlugin) + .add_startup_system(startup) + .add_system(helpers::camera::movement) + .run(); +} diff --git a/src/lib.rs b/src/lib.rs index d00e5da8..af68903d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ use bevy::prelude::{ Bundle, Changed, Component, ComputedVisibility, CoreStage, Deref, GlobalTransform, Plugin, Query, Transform, Visibility, }; +#[cfg(not(feature = "atlas"))] +use map::TilemapTextureSize; use map::{ TilemapGridSize, TilemapSize, TilemapSpacing, TilemapTexture, TilemapTileSize, TilemapType, }; diff --git a/src/map/mod.rs b/src/map/mod.rs index 47cdcbdb..45f7295a 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -250,7 +250,7 @@ impl TilemapSpacing { /// Size of the atlas texture in pixels. #[derive(Component, Default, Clone, Copy, Debug)] -pub(crate) struct TilemapTextureSize { +pub struct TilemapTextureSize { pub x: f32, pub y: f32, } diff --git a/src/render/extract.rs b/src/render/extract.rs index 44b92a2b..f344c6c2 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -21,9 +21,6 @@ use crate::{ use super::RemovedMapEntity; use super::{chunk::PackedTileData, RemovedTileEntity}; -#[cfg(not(feature = "atlas"))] -use bevy::render::render_resource::TextureUsages; - #[derive(Component)] pub struct ExtractedTile { pub entity: Entity, diff --git a/src/render/mod.rs b/src/render/mod.rs index d802a46b..65c278a9 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -308,19 +308,10 @@ fn clear_removed( fn prepare_textures( render_device: Res, mut texture_array_cache: ResMut, - extracted_tilemaps: Query<&ExtractedTilemapTexture>, + extracted_tilemap_textures: Query<&ExtractedTilemapTexture>, ) { - for tilemap in extracted_tilemaps.iter() { - let tile_size: Vec2 = tilemap.tile_size.into(); - let texture_size: Vec2 = tilemap.texture_size.into(); - let spacing: Vec2 = tilemap.tile_spacing.into(); - texture_array_cache.add( - &tilemap.texture.0, - tile_size, - texture_size, - spacing, - tilemap.filtering, - ); + for extracted_texture in extracted_tilemap_textures.iter() { + texture_array_cache.add_extracted_texture(extracted_texture); } texture_array_cache.prepare(&render_device); diff --git a/src/render/queue.rs b/src/render/queue.rs index 8d1f3a58..87d6680a 100644 --- a/src/render/queue.rs +++ b/src/render/queue.rs @@ -152,7 +152,7 @@ pub fn queue_meshes( tilemap_id.0.id(), )) { #[cfg(not(feature = "atlas"))] - if !texture_array_cache.contains(&chunk.texture.0) { + if !texture_array_cache.contains(&chunk.texture) { continue; } @@ -166,7 +166,7 @@ pub fn queue_meshes( .entry(chunk.texture.clone_weak()) .or_insert_with(|| { #[cfg(not(feature = "atlas"))] - let gpu_image = texture_array_cache.get(&chunk.texture.0); + let gpu_image = texture_array_cache.get(&chunk.texture); #[cfg(feature = "atlas")] let gpu_image = gpu_images.get(chunk.texture.image_handle()).unwrap(); render_device.create_bind_group(&BindGroupDescriptor { diff --git a/src/render/texture_array_cache.rs b/src/render/texture_array_cache.rs index b4064470..92d714d8 100644 --- a/src/render/texture_array_cache.rs +++ b/src/render/texture_array_cache.rs @@ -1,8 +1,8 @@ -use std::num::NonZeroU32; - +use crate::render::extract::ExtractedTilemapTexture; +use crate::{TilemapSpacing, TilemapTexture, TilemapTextureSize, TilemapTileSize}; +use bevy::asset::Assets; use bevy::{ - math::Vec2, - prelude::{Handle, Image, Res}, + prelude::{Image, Res}, render::{ render_asset::RenderAssets, render_resource::{ @@ -15,60 +15,116 @@ use bevy::{ }, utils::{HashMap, HashSet}, }; +use std::num::NonZeroU32; #[derive(Default, Debug, Clone)] pub struct TextureArrayCache { - textures: HashMap, GpuImage>, - sizes: HashMap, (Vec2, Vec2, Vec2, FilterMode)>, - prepare_queue: HashSet>, - queue_queue: HashSet>, - bad_flag_queue: HashSet>, + textures: HashMap, + meta_data: HashMap< + TilemapTexture, + ( + u32, + TilemapTileSize, + TilemapTextureSize, + TilemapSpacing, + FilterMode, + ), + >, + prepare_queue: HashSet, + queue_queue: HashSet, + bad_flag_queue: HashSet, } impl TextureArrayCache { - /// Adds an atlas to the texture array cache. - pub fn add( + /// Adds an `ExtractedTilemapTexture` to the texture array cache. + /// + /// Unlike [`add_texture`](TextureArrayCache::add_texture) it does not perform any verification + /// checks, as this is assumed to have been done during [`ExtractedTilemapTexture::new`]. + pub(crate) fn add_extracted_texture(&mut self, extracted_texture: &ExtractedTilemapTexture) { + if !self.meta_data.contains_key(&extracted_texture.texture) { + self.meta_data.insert( + extracted_texture.texture.clone_weak(), + ( + extracted_texture.tile_count, + extracted_texture.tile_size, + extracted_texture.texture_size, + extracted_texture.tile_spacing, + extracted_texture.filtering, + ), + ); + self.prepare_queue + .insert(extracted_texture.texture.clone_weak()); + } + } + + /// Adds a `TilemapTexture` to the texture array cache. + pub fn add_texture( &mut self, - atlas_texture: &Handle, - tile_size: Vec2, - texture_size: Vec2, - tile_spacing: Vec2, - filter: FilterMode, + texture: TilemapTexture, + tile_size: TilemapTileSize, + tile_spacing: TilemapSpacing, + filtering: FilterMode, + image_assets: &Res>, ) { - if !self.sizes.contains_key(atlas_texture) { - self.sizes.insert( - atlas_texture.clone_weak(), - (tile_size, texture_size, tile_spacing, filter), + let (tile_count, texture_size) = match &texture { + TilemapTexture::Single(handle) => { + let image = image_assets.get(handle).expect( + "Expected image to have finished loading if \ + it is being extracted as a texture!", + ); + let texture_size: TilemapTextureSize = image.size().into(); + let tile_count_x = + (texture_size.x + tile_spacing.x) / (tile_size.x + tile_spacing.x); + let tile_count_y = + (texture_size.y + tile_spacing.y) / (tile_size.y + tile_spacing.y); + ((tile_count_x * tile_count_y) as u32, texture_size) + } + TilemapTexture::Vector(handles) => { + for handle in handles { + let image = image_assets.get(handle).expect( + "Expected image to have finished loading if \ + it is being extracted as a texture!", + ); + let this_tile_size: TilemapTileSize = image.size().try_into().unwrap(); + if this_tile_size != tile_size { + panic!( + "Expected all provided image assets to have size {:?}, \ + but found image with size: {:?}", + tile_size, this_tile_size + ); + } + } + (handles.len() as u32, tile_size.into()) + } + }; + + if !self.meta_data.contains_key(&texture) { + self.meta_data.insert( + texture.clone_weak(), + (tile_count, tile_size, texture_size, tile_spacing, filtering), ); - self.prepare_queue.insert(atlas_texture.clone_weak()); + self.prepare_queue.insert(texture.clone_weak()); } } - pub fn get(&self, image_handle: &Handle) -> &GpuImage { - self.textures.get(image_handle).unwrap() + pub fn get(&self, texture: &TilemapTexture) -> &GpuImage { + self.textures.get(texture).unwrap() } - pub fn contains(&self, image_handle: &Handle) -> bool { - self.textures.contains_key(image_handle) + pub fn contains(&self, texture: &TilemapTexture) -> bool { + self.textures.contains_key(texture) } /// Prepares each texture array texture pub fn prepare(&mut self, render_device: &RenderDevice) { let prepare_queue = self.prepare_queue.drain().collect::>(); - for item in prepare_queue { - let (tile_size, atlas_size, spacing, filter) = self.sizes.get(&item).unwrap(); - let tile_count_x = - ((atlas_size.x as f32 + spacing.x) / (tile_size.x + spacing.x)).floor(); - let tile_count_y = - ((atlas_size.y as f32 + spacing.y) / (tile_size.y + spacing.y)).floor(); - let mut count = (tile_count_x * tile_count_y) as u32; + for texture in prepare_queue { + let (count, tile_size, _, _, filter) = self.meta_data.get(&texture).unwrap(); // Fixes weird cubemap bug. - if count == 6 { - count += 1; - } + let count = if *count == 6 { count + 1 } else { *count }; - let texture = render_device.create_texture(&TextureDescriptor { + let gpu_texture = render_device.create_texture(&TextureDescriptor { label: Some("texture_array"), size: Extent3d { width: tile_size.x as u32, @@ -97,7 +153,7 @@ impl TextureArrayCache { border_color: None, }); - let texture_view = texture.create_view(&TextureViewDescriptor { + let texture_view = gpu_texture.create_view(&TextureViewDescriptor { label: Some("texture_array_view"), format: None, dimension: Some(TextureViewDimension::D2Array), @@ -110,14 +166,14 @@ impl TextureArrayCache { let gpu_image = GpuImage { texture_format: TextureFormat::bevy_default(), - texture, + texture: gpu_texture, sampler, texture_view, - size: Vec2::new(tile_size.x, tile_size.y), + size: tile_size.into(), }; - self.textures.insert(item.clone_weak(), gpu_image); - self.queue_queue.insert(item.clone_weak()); + self.textures.insert(texture.clone_weak(), gpu_image); + self.queue_queue.insert(texture.clone_weak()); } } @@ -125,67 +181,120 @@ impl TextureArrayCache { &mut self, render_device: &RenderDevice, render_queue: &RenderQueue, - gpu_images: &Res>, + render_images: &Res>, ) { let queue_queue = self.queue_queue.drain().collect::>(); - for item in queue_queue { - let atlas_image = if let Some(atlas_image) = gpu_images.get(&item) { - atlas_image - } else { - self.prepare_queue.insert(item); - continue; - }; + for texture in queue_queue.iter() { + match &texture { + TilemapTexture::Single(handle) => { + let gpu_image = if let Some(gpu_image) = render_images.get(&handle) { + gpu_image + } else { + self.prepare_queue.insert(texture.clone_weak()); + continue; + }; - let (tile_size, atlas_size, spacing, _) = self.sizes.get(&item).unwrap(); - let array_gpu_image = self.textures.get(&item).unwrap(); - let tile_count_x = - ((atlas_size.x as f32 + spacing.x) / (tile_size.x + spacing.x)).floor(); - let tile_count_y = - ((atlas_size.y as f32 + spacing.y) / (tile_size.y + spacing.y)).floor(); - let count = (tile_count_x * tile_count_y) as u32; - - let mut command_encoder = - render_device.create_command_encoder(&CommandEncoderDescriptor { - label: Some("create_texture_array_from_atlas"), - }); - - for i in 0..count { - let columns = (atlas_size.x as f32 + spacing.x) / (tile_size.x + spacing.x); - let sprite_sheet_x: f32 = (i as f32 % columns).floor() * (tile_size.x + spacing.x); - let sprite_sheet_y: f32 = (i as f32 / columns).floor() * (tile_size.y + spacing.y); - - command_encoder.copy_texture_to_texture( - ImageCopyTexture { - texture: &atlas_image.texture, - mip_level: 0, - origin: Origin3d { - x: sprite_sheet_x as u32, - y: sprite_sheet_y as u32, - z: 0, - }, - aspect: TextureAspect::All, - }, - ImageCopyTexture { - texture: &array_gpu_image.texture, - mip_level: 0, - origin: Origin3d { - x: 0, - y: 0, - z: i as u32, - }, - aspect: TextureAspect::All, - }, - Extent3d { - width: tile_size.x as u32, - height: tile_size.y as u32, - depth_or_array_layers: 1, - }, - ); - } + let (count, tile_size, texture_size, spacing, _) = + self.meta_data.get(&texture).unwrap(); + let array_gpu_image = self.textures.get(&texture).unwrap(); + let count = *count; + + let mut command_encoder = + render_device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("create_texture_array_from_atlas"), + }); + + for i in 0..count { + let columns = (texture_size.x as f32 + spacing.x as f32) + / (tile_size.x as f32 + spacing.x as f32); + let sprite_sheet_x: f32 = + (i as f32 % columns).floor() * (tile_size.x + spacing.x) as f32; + let sprite_sheet_y: f32 = + (i as f32 / columns).floor() * (tile_size.y + spacing.y) as f32; + + command_encoder.copy_texture_to_texture( + ImageCopyTexture { + texture: &gpu_image.texture, + mip_level: 0, + origin: Origin3d { + x: sprite_sheet_x as u32, + y: sprite_sheet_y as u32, + z: 0, + }, + aspect: TextureAspect::All, + }, + ImageCopyTexture { + texture: &array_gpu_image.texture, + mip_level: 0, + origin: Origin3d { + x: 0, + y: 0, + z: i as u32, + }, + aspect: TextureAspect::All, + }, + Extent3d { + width: tile_size.x as u32, + height: tile_size.y as u32, + depth_or_array_layers: 1, + }, + ); + } - let command_buffer = command_encoder.finish(); - render_queue.submit(vec![command_buffer]); + let command_buffer = command_encoder.finish(); + render_queue.submit(vec![command_buffer]); + } + TilemapTexture::Vector(handles) => { + let mut gpu_images = Vec::with_capacity(handles.len()); + for handle in handles { + if let Some(gpu_image) = render_images.get(handle) { + gpu_images.push(gpu_image) + } else { + self.prepare_queue.insert(texture.clone_weak()); + continue; + } + } + + let (count, tile_size, _, _, _) = self.meta_data.get(texture).unwrap(); + let array_gpu_image = self.textures.get(texture).unwrap(); + let count = *count; + + let mut command_encoder = + render_device.create_command_encoder(&CommandEncoderDescriptor { + label: Some("create_texture_array_from_handles_vec"), + }); + + for i in 0..count { + command_encoder.copy_texture_to_texture( + ImageCopyTexture { + texture: &gpu_images[i as usize].texture, + mip_level: 0, + origin: Origin3d { x: 0, y: 0, z: 0 }, + aspect: TextureAspect::All, + }, + ImageCopyTexture { + texture: &array_gpu_image.texture, + mip_level: 0, + origin: Origin3d { + x: 0, + y: 0, + z: i as u32, + }, + aspect: TextureAspect::All, + }, + Extent3d { + width: tile_size.x as u32, + height: tile_size.y as u32, + depth_or_array_layers: 1, + }, + ); + } + + let command_buffer = command_encoder.finish(); + render_queue.submit(vec![command_buffer]); + } + } } } } From 1b3eda3281618b6c45c71baca3dc0463a71f2b1c Mon Sep 17 00:00:00 2001 From: Brian Merchant Date: Sun, 2 Oct 2022 09:48:25 -0700 Subject: [PATCH 4/4] Fix clippy lints. --- src/render/extract.rs | 2 +- src/render/texture_array_cache.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/render/extract.rs b/src/render/extract.rs index f344c6c2..e44763d8 100644 --- a/src/render/extract.rs +++ b/src/render/extract.rs @@ -124,7 +124,7 @@ impl ExtractedTilemapTexture { ExtractedTilemapTexture { tilemap_id: TilemapId(tilemap_entity), - texture: texture.clone(), + texture, tile_size, tile_spacing, filtering, diff --git a/src/render/texture_array_cache.rs b/src/render/texture_array_cache.rs index 92d714d8..e5036a05 100644 --- a/src/render/texture_array_cache.rs +++ b/src/render/texture_array_cache.rs @@ -188,7 +188,7 @@ impl TextureArrayCache { for texture in queue_queue.iter() { match &texture { TilemapTexture::Single(handle) => { - let gpu_image = if let Some(gpu_image) = render_images.get(&handle) { + let gpu_image = if let Some(gpu_image) = render_images.get(handle) { gpu_image } else { self.prepare_queue.insert(texture.clone_weak()); @@ -196,8 +196,8 @@ impl TextureArrayCache { }; let (count, tile_size, texture_size, spacing, _) = - self.meta_data.get(&texture).unwrap(); - let array_gpu_image = self.textures.get(&texture).unwrap(); + self.meta_data.get(texture).unwrap(); + let array_gpu_image = self.textures.get(texture).unwrap(); let count = *count; let mut command_encoder =