diff --git a/.vscode/launch.json b/.vscode/launch.json index 59f5d46f6b..d581eeb476 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1416,6 +1416,25 @@ "args": [], "cwd": "${workspaceFolder}" }, + { + "type": "lldb", + "request": "launch", + "name": "Debug example 'sprite_sheet'", + "env": { "CARGO_MANIFEST_DIR": "${workspaceFolder}" }, + "cargo": { + "args": [ + "build", + "--example=sprite_sheet", + "--package=bevy" + ], + "filter": { + "name": "sprite_sheet", + "kind": "example" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, { "type": "lldb", "request": "launch", diff --git a/CREDITS.md b/CREDITS.md index efb6ce691f..6791b8d4a3 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -9,4 +9,8 @@ ## Inspiration * amethyst -* coffee \ No newline at end of file +* coffee + +## Assets + +* Generic RPG Pack (CC0 license) by [Bakudas](https://twitter.com/bakudas) and [Gabe Fern](https://twitter.com/_Gabrielfer) \ No newline at end of file diff --git a/assets/textures/character_run.png b/assets/textures/character_run.png new file mode 100644 index 0000000000..c8f57e34cf Binary files /dev/null and b/assets/textures/character_run.png differ diff --git a/crates/bevy_derive/src/uniforms.rs b/crates/bevy_derive/src/uniforms.rs index 42b0c7b290..fa1712947f 100644 --- a/crates/bevy_derive/src/uniforms.rs +++ b/crates/bevy_derive/src/uniforms.rs @@ -1,11 +1,10 @@ +use crate::modules::{get_modules, get_path}; use darling::FromMeta; use inflector::Inflector; -use crate::modules::{get_modules, get_path}; use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Path}; -// TODO: ensure shader_def and instance/vertex are mutually exclusive #[derive(FromMeta, Debug, Default)] struct UniformAttributeArgs { #[darling(default)] @@ -88,6 +87,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { let mut texture_and_sampler_name_strings = Vec::new(); let mut texture_and_sampler_name_idents = Vec::new(); let mut field_infos = Vec::new(); + let mut get_field_bind_types = Vec::new(); let mut vertex_buffer_field_names_pascal = Vec::new(); let mut vertex_buffer_field_types = Vec::new(); @@ -98,6 +98,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { for (f, attrs) in field_attributes.iter() { let field_name = f.ident.as_ref().unwrap().to_string(); if !attrs.ignore { + let active_uniform_field_name = &f.ident; active_uniform_field_names.push(&f.ident); active_uniform_field_name_strings.push(field_name.clone()); let uniform = format!("{}_{}", struct_name, field_name); @@ -117,6 +118,19 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { is_instanceable: #is_instanceable, })); + if attrs.buffer { + get_field_bind_types.push(quote!({ + let bind_type = self.#active_uniform_field_name.get_bind_type(); + let size = if let Some(#bevy_render_path::shader::FieldBindType::Uniform { size }) = bind_type { + size + } else { + panic!("Uniform field was labeled as a 'buffer', but it does not have a compatible type.") + }; + Some(#bevy_render_path::shader::FieldBindType::Buffer { size }) + })) + } else { + get_field_bind_types.push(quote!(self.#active_uniform_field_name.get_bind_type())) + } } if attrs.shader_def { @@ -192,7 +206,7 @@ pub fn derive_uniforms(input: TokenStream) -> TokenStream { fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> { use #bevy_render_path::shader::GetFieldBindType; match name { - #(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)* + #(#active_uniform_field_name_strings => #get_field_bind_types,)* _ => None, } } @@ -314,4 +328,4 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream { } } }) -} \ No newline at end of file +} diff --git a/crates/bevy_render/src/pipeline/binding.rs b/crates/bevy_render/src/pipeline/binding.rs index 38a9e0a694..8318bd8008 100644 --- a/crates/bevy_render/src/pipeline/binding.rs +++ b/crates/bevy_render/src/pipeline/binding.rs @@ -15,7 +15,7 @@ pub enum BindType { dynamic: bool, properties: Vec, }, - Buffer { + StorageBuffer { dynamic: bool, readonly: bool, }, diff --git a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs index a56796d71f..987c982f58 100644 --- a/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/texture_copy_node.rs @@ -54,7 +54,7 @@ impl Node for TextureCopyNode { render_context.copy_buffer_to_texture( texture_buffer, 0, - (4 * texture.width) as u32, + 4 * texture.size.x() as u32, texture_resource, [0, 0, 0], 0, diff --git a/crates/bevy_render/src/render_graph/nodes/uniform_node.rs b/crates/bevy_render/src/render_graph/nodes/uniform_node.rs index 370591df06..c6b57ff732 100644 --- a/crates/bevy_render/src/render_graph/nodes/uniform_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/uniform_node.rs @@ -83,7 +83,7 @@ where fn increment_uniform_counts(&mut self, uniforms: &T) { for (i, field_info) in T::get_field_infos().iter().enumerate() { - if let Some(FieldBindType::Uniform { size }) = + if let Some(FieldBindType::Uniform { size }) | Some(FieldBindType::Buffer { size }) = uniforms.get_field_bind_type(&field_info.name) { if let Some((ref _name, ref mut buffer_array_status)) = self.uniform_arrays[i] { @@ -186,8 +186,9 @@ where for (i, field_info) in T::get_field_infos().iter().enumerate() { let bind_type = uniforms.get_field_bind_type(&field_info.name); match bind_type { - Some(FieldBindType::Uniform { size }) => { + Some(FieldBindType::Uniform { size }) | Some(FieldBindType::Buffer { size }) => { let (_name, uniform_buffer_status) = self.uniform_arrays[i].as_mut().unwrap(); + let range = 0..size as u64; let (target_buffer, target_offset) = if dynamic_uniforms { let buffer = uniform_buffer_status.buffer.unwrap(); let index = uniform_buffer_status @@ -199,31 +200,38 @@ where dynamic_index: Some( (index * uniform_buffer_status.aligned_size) as u32, ), - range: 0..size as u64, + range, }, ); (buffer, index * uniform_buffer_status.aligned_size) } else { - let resource = - match render_resource_assignments.get(field_info.uniform_name) { - Some(assignment) => assignment.get_resource(), - None => { - let resource = render_resources.create_buffer(BufferInfo { - size, - buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, - ..Default::default() - }); - render_resource_assignments.set( - &field_info.uniform_name, - RenderResourceAssignment::Buffer { - resource, - range: 0..size as u64, - dynamic_index: None, - }, - ); - resource - } - }; + let resource = match render_resource_assignments + .get(field_info.uniform_name) + { + Some(assignment) => assignment.get_resource(), + None => { + let usage = if let Some(FieldBindType::Buffer { .. }) = bind_type { + BufferUsage::STORAGE + } else { + BufferUsage::UNIFORM + }; + let resource = render_resources.create_buffer(BufferInfo { + size, + buffer_usage: BufferUsage::COPY_DST | usage, + ..Default::default() + }); + + render_resource_assignments.set( + &field_info.uniform_name, + RenderResourceAssignment::Buffer { + resource, + range, + dynamic_index: None, + }, + ); + resource + } + }; (resource, 0) }; @@ -232,14 +240,16 @@ where + (uniform_buffer_status.queued_buffer_writes.len() * uniform_buffer_status.item_size); let uniform_byte_len = uniforms.uniform_byte_len(&field_info.uniform_name); - if uniform_byte_len > 0 - { + if uniform_byte_len > 0 { if size != uniform_byte_len { panic!("The number of bytes produced for {} do not match the expected count. Actual: {}. Expected: {}.", field_info.uniform_name, uniform_byte_len, size); } - uniforms.write_uniform_bytes(&field_info.uniform_name, &mut staging_buffer - [staging_buffer_start..(staging_buffer_start + uniform_byte_len)]); + uniforms.write_uniform_bytes( + &field_info.uniform_name, + &mut staging_buffer + [staging_buffer_start..(staging_buffer_start + uniform_byte_len)], + ); } else { panic!( "failed to get data from uniform: {}", @@ -254,7 +264,8 @@ where offset: target_offset, }); } - _ => {} + Some(FieldBindType::Texture) => { /* ignore textures */ } + None => { /* ignore None */ } } } } @@ -680,7 +691,7 @@ fn setup_uniform_texture_resources( entities_waiting_for_assets: &EntitiesWaitingForAssets, render_resource_assignments: &mut RenderResourceAssignments, ) where - T: AsUniforms, + T: AsUniforms, { for field_info in T::get_field_infos().iter() { let bind_type = uniforms.get_field_bind_type(&field_info.name); diff --git a/crates/bevy_render/src/render_resource/buffer.rs b/crates/bevy_render/src/render_resource/buffer.rs index 5a82a0cbfc..87ea3e3e2a 100644 --- a/crates/bevy_render/src/render_resource/buffer.rs +++ b/crates/bevy_render/src/render_resource/buffer.rs @@ -1,6 +1,7 @@ bitflags::bitflags! { #[repr(transparent)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "trace", derive(Serialize))] + #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BufferUsage: u32 { const MAP_READ = 1; const MAP_WRITE = 2; @@ -11,17 +12,5 @@ bitflags::bitflags! { const UNIFORM = 64; const STORAGE = 128; const INDIRECT = 256; - const STORAGE_READ = 512; - const NONE = 0; - /// The combination of all read-only usages. - const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits | - Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits | - Self::STORAGE_READ.bits | Self::INDIRECT.bits; - /// The combination of all write-only and read-write usages. - const WRITE_ALL = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE.bits; - /// The combination of all usages that the are guaranteed to be be ordered by the hardware. - /// If a usage is not ordered, then even if it doesn't change between draw calls, there - /// still need to be pipeline barriers inserted for synchronization. - const ORDERED = Self::READ_ALL.bits; } -} +} \ No newline at end of file diff --git a/crates/bevy_render/src/render_resource/resource_info.rs b/crates/bevy_render/src/render_resource/resource_info.rs index b1f67f3928..369b6b1480 100644 --- a/crates/bevy_render/src/render_resource/resource_info.rs +++ b/crates/bevy_render/src/render_resource/resource_info.rs @@ -10,7 +10,7 @@ impl Default for BufferInfo { fn default() -> Self { BufferInfo { size: 0, - buffer_usage: BufferUsage::NONE, + buffer_usage: BufferUsage::empty(), } } } diff --git a/crates/bevy_render/src/shader/shader_reflect.rs b/crates/bevy_render/src/shader/shader_reflect.rs index 39aab47b8d..5096c3f7d7 100644 --- a/crates/bevy_render/src/shader/shader_reflect.rs +++ b/crates/bevy_render/src/shader/shader_reflect.rs @@ -198,8 +198,8 @@ fn reflect_binding(binding: &ReflectDescriptorBinding) -> BindingDescriptor { }, ), ReflectDescriptorType::StorageBuffer => ( - &binding.name, - BindType::Buffer { + &type_description.type_name, + BindType::StorageBuffer { dynamic: false, readonly: true, }, diff --git a/crates/bevy_render/src/shader/uniform.rs b/crates/bevy_render/src/shader/uniform.rs index eef0cc0953..07f297cd2c 100644 --- a/crates/bevy_render/src/shader/uniform.rs +++ b/crates/bevy_render/src/shader/uniform.rs @@ -70,8 +70,9 @@ impl ShaderDefSuffixProvider for bool { #[derive(Clone, Debug, Eq, PartialEq)] pub enum FieldBindType { + // TODO: maybe change this to Buffer Uniform { size: usize }, - Buffer, + Buffer { size: usize }, Texture, } diff --git a/crates/bevy_render/src/texture/png_texture_loader.rs b/crates/bevy_render/src/texture/png_texture_loader.rs index 02d4dbf858..9a9c16c710 100644 --- a/crates/bevy_render/src/texture/png_texture_loader.rs +++ b/crates/bevy_render/src/texture/png_texture_loader.rs @@ -2,6 +2,7 @@ use super::Texture; use anyhow::Result; use bevy_asset::AssetLoader; use std::path::Path; +use glam::Vec2; #[derive(Clone, Default)] pub struct PngTextureLoader; @@ -14,8 +15,7 @@ impl AssetLoader for PngTextureLoader { reader.next_frame(&mut data)?; Ok(Texture { data, - width: info.width as usize, - height: info.height as usize, + size: Vec2::new(info.width as f32, info.height as f32), }) } fn extensions(&self) -> &[&str] { diff --git a/crates/bevy_render/src/texture/texture.rs b/crates/bevy_render/src/texture/texture.rs index 9c277dae65..eea338e40c 100644 --- a/crates/bevy_render/src/texture/texture.rs +++ b/crates/bevy_render/src/texture/texture.rs @@ -8,6 +8,7 @@ use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_derive::FromResources; use legion::prelude::*; use std::{collections::HashSet, fs::File}; +use glam::Vec2; pub const TEXTURE_ASSET_INDEX: usize = 0; pub const SAMPLER_ASSET_INDEX: usize = 1; @@ -18,13 +19,12 @@ pub enum TextureType { pub struct Texture { pub data: Vec, - pub width: usize, - pub height: usize, + pub size: Vec2, } impl Texture { pub fn aspect(&self) -> f32 { - self.height as f32 / self.width as f32 + self.size.y() / self.size.x() } pub fn load(descriptor: TextureType) -> Self { @@ -41,8 +41,7 @@ impl Texture { Texture { data, - width, - height, + size: Vec2::new(width as f32, height as f32) } } diff --git a/crates/bevy_render/src/texture/texture_descriptor.rs b/crates/bevy_render/src/texture/texture_descriptor.rs index fc85624e86..d19d28ecfc 100644 --- a/crates/bevy_render/src/texture/texture_descriptor.rs +++ b/crates/bevy_render/src/texture/texture_descriptor.rs @@ -14,8 +14,8 @@ impl From<&Texture> for TextureDescriptor { fn from(texture: &Texture) -> Self { TextureDescriptor { size: Extent3d { - height: texture.height as u32, - width: texture.width as u32, + width: texture.size.x() as u32, + height: texture.size.y() as u32, depth: 1, }, mip_level_count: 1, diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index ebbc4fc191..c88a64be10 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -37,10 +37,6 @@ impl AppPlugin for SpritePlugin { .add_system_to_stage( stage::POST_UPDATE, asset_shader_def_system::.system(), - ) - .init_system_to_stage( - bevy_render::stage::RENDER_RESOURCE, - sprite_sheet_resource_provider_system, ); let resources = app.resources(); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index e73e1414a2..d6c591bc92 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -135,7 +135,7 @@ impl SpriteRenderGraphBuilder for RenderGraph { self.add_system_node( node::SPRITE_SHEET, - AssetUniformNode::::new(true), + AssetUniformNode::::new(false), ); self.add_system_node( diff --git a/crates/bevy_sprite/src/render/sprite_sheet.frag b/crates/bevy_sprite/src/render/sprite_sheet.frag index 9995374756..289ba6729a 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.frag +++ b/crates/bevy_sprite/src/render/sprite_sheet.frag @@ -4,11 +4,11 @@ layout(location = 0) in vec2 v_Uv; layout(location = 0) out vec4 o_Target; -layout(set = 1, binding = 1) uniform texture2D SpriteSheet_texture; -layout(set = 1, binding = 2) uniform sampler SpriteSheet_texture_sampler; +layout(set = 1, binding = 2) uniform texture2D SpriteSheet_texture; +layout(set = 1, binding = 3) uniform sampler SpriteSheet_texture_sampler; void main() { o_Target = texture( sampler2D(SpriteSheet_texture, SpriteSheet_texture_sampler), - v_Uv);; + v_Uv); } diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index 95c58ad67b..5109665a6c 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -4,18 +4,9 @@ layout(location = 0) in vec3 Vertex_Position; layout(location = 1) in vec3 Vertex_Normal; layout(location = 2) in vec2 Vertex_Uv; -// TODO: consider swapping explicit mesh binding for this const -// const vec2 positions[4] = vec2[]( -// vec2(0.5, -0.5), -// vec2(-0.5, -0.5), -// vec2(0.5, 0.5), -// vec2(-0.5, 0.5) -// ); - // TODO: uncomment when instancing is implemented // sprite // layout(location = 0) in vec3 Sprite_Position; -// // this is a vec2 instead of an int due to WebGPU limitations // layout(location = 1) in int Sprite_Index; layout(location = 0) out vec2 v_Uv; @@ -24,30 +15,37 @@ layout(set = 0, binding = 0) uniform Camera2d { mat4 ViewProj; }; +// TODO: merge dimensions into "sprites" buffer when that is supported in the Uniforms derive abstraction +layout(set = 1, binding = 0) uniform SpriteSheet_dimensions { + vec2 Dimensions; +}; + struct Rect { vec2 begin; vec2 end; }; -layout(set = 1, binding = 0) buffer SpriteSheet_sprites { +layout(set = 1, binding = 1) buffer SpriteSheet_sprites { Rect[] Sprites; }; + layout(set = 2, binding = 0) uniform SpriteSheetSprite { vec3 SpriteSheetSprite_position; + float SpriteSheetSprite_scale; uint SpriteSheetSprite_index; }; void main() { - Rect sprite_rect = Sprites[SpriteSheetSprite_index]; - vec2 dimensions = sprite_rect.end - sprite_rect.begin; - vec2 vertex_position = Vertex_Position.xy * dimensions; + Rect sprite_rect = Sprites[SpriteSheetSprite_index]; + vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin; + vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * SpriteSheetSprite_scale, 0.0) + SpriteSheetSprite_position; vec2 uvs[4] = vec2[]( - vec2(sprite_rect.end.x, sprite_rect.begin.y), + vec2(sprite_rect.begin.x, sprite_rect.end.y), sprite_rect.begin, - sprite_rect.end, - vec2(sprite_rect.begin.x, sprite_rect.end.y) + vec2(sprite_rect.end.x, sprite_rect.begin.y), + sprite_rect.end ); - v_Uv = uvs[gl_VertexIndex]; - gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + SpriteSheetSprite_position, 1.0); + v_Uv = uvs[gl_VertexIndex] / Dimensions; + gl_Position = ViewProj * vec4(vertex_position, 1.0); } \ No newline at end of file diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 559e99142f..2b4d642828 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -27,7 +27,7 @@ pub fn sprite_system() -> Box { if let Some(texture_handle) = material.texture { if let Some(texture) = textures.get(&texture_handle) { let aspect = texture.aspect(); - *rect.size.x_mut() = texture.width as f32 * sprite.scale; + *rect.size.x_mut() = texture.size.x() * sprite.scale; *rect.size.y_mut() = rect.size.x() * aspect; } } diff --git a/crates/bevy_sprite/src/sprite_sheet.rs b/crates/bevy_sprite/src/sprite_sheet.rs index b957fbece8..fdc0e6009c 100644 --- a/crates/bevy_sprite/src/sprite_sheet.rs +++ b/crates/bevy_sprite/src/sprite_sheet.rs @@ -1,113 +1,52 @@ use crate::Rect; -use bevy_app::{Events, GetEventReader}; -use bevy_asset::{AssetEvent, Assets, Handle}; -use bevy_core::bytes::AsBytes; +use bevy_asset::Handle; use bevy_derive::{Bytes, Uniform, Uniforms}; -use bevy_render::{ - render_resource::{BufferInfo, BufferUsage, RenderResourceAssignment, ResourceInfo}, - renderer::{RenderResourceContext, RenderResources}, - texture::Texture, - Renderable, -}; -use glam::{Vec3, Vec4}; -use legion::prelude::*; -use std::collections::HashSet; +use bevy_render::texture::Texture; +use glam::{Vec2, Vec3}; #[derive(Uniforms)] pub struct SpriteSheet { pub texture: Handle, + // TODO: add support to Uniforms derive to write dimensions and sprites to the same buffer + pub dimensions: Vec2, + #[uniform(buffer)] pub sprites: Vec, } -// NOTE: cannot do unsafe impl Byteable here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out -// Bytes for Byteable. https://github.com/bitshifter/glam-rs/issues/36 +// NOTE: cannot do `unsafe impl Byteable` here because Vec3 takes up the space of a Vec4. If/when glam changes this we can swap out +// Bytes for Byteable as a micro-optimization. https://github.com/bitshifter/glam-rs/issues/36 #[derive(Uniform, Bytes, Default)] pub struct SpriteSheetSprite { pub position: Vec3, + pub scale: f32, pub index: u32, } -pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0; - -fn remove_sprite_sheet_resource( - render_resources: &dyn RenderResourceContext, - handle: Handle, -) { - if let Some(resource) = - render_resources.get_asset_resource(handle, SPRITE_SHEET_BUFFER_ASSET_INDEX) - { - render_resources.remove_buffer(resource); - render_resources.remove_asset_resource(handle, SPRITE_SHEET_BUFFER_ASSET_INDEX); +impl SpriteSheet { + pub fn from_grid( + texture: Handle, + size: Vec2, + columns: usize, + rows: usize, + ) -> SpriteSheet { + let sprite_width = size.x() / columns as f32; + let sprite_height = size.y() / rows as f32; + let mut sprites = Vec::new(); + for y in 0..rows { + for x in 0..columns { + sprites.push(Rect { + min: Vec2::new(x as f32 * sprite_width, y as f32 * sprite_height), + max: Vec2::new( + (x + 1) as f32 * sprite_width, + (y + 1) as f32 * sprite_height, + ), + }) + } + } + SpriteSheet { + dimensions: size, + sprites, + texture, + } } } - -pub fn sprite_sheet_resource_provider_system(resources: &mut Resources) -> Box { - let mut sprite_sheet_event_reader = resources.get_event_reader::>(); - (move |world: &mut SubWorld, - render_resources: Res, - sprite_sheets: Res>, - sprite_sheet_events: Res>>, - query: &mut Query<(Read>, Write)>| { - let render_resources = &*render_resources.context; - let mut changed_sprite_sheets = HashSet::new(); - for event in sprite_sheet_event_reader.iter(&sprite_sheet_events) { - match event { - AssetEvent::Created { handle } => { - changed_sprite_sheets.insert(*handle); - } - AssetEvent::Modified { handle } => { - changed_sprite_sheets.insert(*handle); - remove_sprite_sheet_resource(render_resources, *handle); - } - AssetEvent::Removed { handle } => { - remove_sprite_sheet_resource(render_resources, *handle); - // if sprite sheet was modified and removed in the same update, ignore the modification - // events are ordered so future modification events are ok - changed_sprite_sheets.remove(handle); - } - } - } - - for changed_sprite_sheet_handle in changed_sprite_sheets.iter() { - if let Some(sprite_sheet) = sprite_sheets.get(changed_sprite_sheet_handle) { - let sprite_sheet_bytes = sprite_sheet.sprites.as_slice().as_bytes(); - let sprite_sheet_buffer = render_resources.create_buffer_with_data( - BufferInfo { - buffer_usage: BufferUsage::STORAGE, - ..Default::default() - }, - &sprite_sheet_bytes, - ); - - render_resources.set_asset_resource( - *changed_sprite_sheet_handle, - sprite_sheet_buffer, - SPRITE_SHEET_BUFFER_ASSET_INDEX, - ); - } - } - - // TODO: remove this when batching is implemented - for (handle, mut renderable) in query.iter_mut(world) { - if let Some(sprite_sheet_buffer) = - render_resources.get_asset_resource(*handle, SPRITE_SHEET_BUFFER_ASSET_INDEX) - { - let mut buffer_size = None; - render_resources.get_resource_info(sprite_sheet_buffer, &mut |info| { - if let Some(ResourceInfo::Buffer(BufferInfo { size, .. })) = info { - buffer_size = Some(*size as u64) - } - }); - renderable.render_resource_assignments.set( - "SpriteSheet", - RenderResourceAssignment::Buffer { - dynamic_index: None, - range: 0..buffer_size.unwrap(), - resource: sprite_sheet_buffer, - }, - ) - } - } - }) - .system() -} diff --git a/crates/bevy_wgpu/src/wgpu_type_converter.rs b/crates/bevy_wgpu/src/wgpu_type_converter.rs index 28e71173b4..1288775aef 100644 --- a/crates/bevy_wgpu/src/wgpu_type_converter.rs +++ b/crates/bevy_wgpu/src/wgpu_type_converter.rs @@ -165,7 +165,7 @@ impl WgpuFrom<&BindType> for wgpu::BindingType { dynamic, properties: _, } => wgpu::BindingType::UniformBuffer { dynamic: *dynamic }, - BindType::Buffer { dynamic, readonly } => wgpu::BindingType::StorageBuffer { + BindType::StorageBuffer { dynamic, readonly } => wgpu::BindingType::StorageBuffer { dynamic: *dynamic, readonly: *readonly, }, diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs index 1ef9713842..62262882e1 100644 --- a/examples/2d/sprite_sheet.rs +++ b/examples/2d/sprite_sheet.rs @@ -1,36 +1,59 @@ -use bevy::prelude::*; -use bevy::input::system::exit_on_esc_system; -use bevy_sprite::{Rect, SpriteSheet}; +use bevy::{input::system::exit_on_esc_system, prelude::*}; +use bevy_sprite::{SpriteSheet, SpriteSheetSprite}; fn main() { App::build() + .init_resource::() .add_default_plugins() .add_startup_system(setup.system()) .init_system(exit_on_esc_system) + .add_system(animate_sprite_system.system()) .run(); } +#[derive(Default)] +struct State { + elapsed: f32, +} + +fn animate_sprite_system( + mut state: ResMut, + time: Res