diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index 3ed024ebd4..4b23eb8f22 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -119,7 +119,7 @@ pub fn derive_uniform(input: TokenStream) -> TokenStream { } fn get_field_bind_type(&self, name: &str) -> Option<#bevy_render_path::shader::FieldBindType> { - use #bevy_render_path::shader::AsFieldBindType; + use #bevy_render_path::shader::GetFieldBindType; match name { #struct_name_string => self.get_bind_type(), _ => None, @@ -453,7 +453,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::AsFieldBindType; + use #bevy_render_path::shader::GetFieldBindType; match name { #(#active_uniform_field_name_strings => self.#active_uniform_field_names.get_bind_type(),)* _ => None, diff --git a/crates/bevy_render/src/pipeline/pipeline_layout.rs b/crates/bevy_render/src/pipeline/pipeline_layout.rs index 9a4d80ce2b..40e858fc5a 100644 --- a/crates/bevy_render/src/pipeline/pipeline_layout.rs +++ b/crates/bevy_render/src/pipeline/pipeline_layout.rs @@ -1,5 +1,5 @@ use super::{BindGroupDescriptor, VertexBufferDescriptor, VertexBufferDescriptors}; -use crate::shader::ShaderLayout; +use crate::shader::{GL_VERTEX_INDEX, ShaderLayout}; use std::{collections::HashMap, hash::Hash}; #[derive(Clone, Debug, Default)] @@ -65,6 +65,9 @@ impl PipelineLayout { vertex_buffer_descriptors.get(&vertex_buffer_descriptor.name) { vertex_buffer_descriptor.sync_with_descriptor(graph_descriptor); + } else if vertex_buffer_descriptor.name == GL_VERTEX_INDEX { + // GL_VERTEX_INDEX is a special attribute set on our behalf + continue; } else { panic!( "Encountered unsupported Vertex Buffer: {}", @@ -84,6 +87,7 @@ pub struct UniformProperty { #[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum UniformPropertyType { // TODO: Use VertexFormat here + UInt, Int, IVec2, Float, @@ -100,6 +104,7 @@ pub enum UniformPropertyType { impl UniformPropertyType { pub fn get_size(&self) -> u64 { match self { + UniformPropertyType::UInt => 4, UniformPropertyType::Int => 4, UniformPropertyType::IVec2 => 4 * 2, UniformPropertyType::Float => 4, diff --git a/crates/bevy_render/src/shader/shader_reflect.rs b/crates/bevy_render/src/shader/shader_reflect.rs index 861de04e54..39aab47b8d 100644 --- a/crates/bevy_render/src/shader/shader_reflect.rs +++ b/crates/bevy_render/src/shader/shader_reflect.rs @@ -5,6 +5,7 @@ use crate::{ }, texture::{TextureComponentType, TextureViewDimension}, }; +use bevy_core::bytes::AsBytes; use spirv_reflect::{ types::{ ReflectDescriptorBinding, ReflectDescriptorSet, ReflectDescriptorType, ReflectDimension, @@ -12,7 +13,6 @@ use spirv_reflect::{ }, ShaderModule, }; -use bevy_core::bytes::AsBytes; use std::collections::HashSet; // use rspirv::{binary::Parser, dr::Loader, lift::LiftContext}; @@ -35,6 +35,8 @@ pub struct ShaderLayout { pub entry_point: String, } +pub const GL_VERTEX_INDEX: &str = "gl_VertexIndex"; + impl ShaderLayout { pub fn from_spirv(spirv_data: &[u32], bevy_conventions: bool) -> ShaderLayout { match ShaderModule::load_u8_data(spirv_data.as_bytes()) { @@ -63,21 +65,25 @@ impl ShaderLayout { let mut instance = false; let current_buffer_name = { if bevy_conventions { - let parts = vertex_attribute_descriptor - .name - .splitn(3, "_") - .collect::>(); - if parts.len() == 3 { - if parts[0] == "I" { - instance = true; - parts[1].to_string() - } else { - parts[0].to_string() - } - } else if parts.len() == 2 { - parts[0].to_string() + if vertex_attribute_descriptor.name == GL_VERTEX_INDEX { + GL_VERTEX_INDEX.to_string() } else { - panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position"); + let parts = vertex_attribute_descriptor + .name + .splitn(3, "_") + .collect::>(); + if parts.len() == 3 { + if parts[0] == "I" { + instance = true; + parts[1].to_string() + } else { + parts[0].to_string() + } + } else if parts.len() == 2 { + parts[0].to_string() + } else { + panic!("Vertex attributes must follow the form BUFFERNAME_PROPERTYNAME. For example: Vertex_Position"); + } } } else { "DefaultVertex".to_string() @@ -279,6 +285,7 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform } } else { match (number_type, traits.numeric.vector.component_count) { + (NumberType::UInt, 0) => UniformPropertyType::UInt, (NumberType::Int, 0) => UniformPropertyType::Int, (NumberType::Int, 2) => UniformPropertyType::IVec2, (NumberType::Float, 0) => UniformPropertyType::Float, diff --git a/crates/bevy_render/src/shader/uniform.rs b/crates/bevy_render/src/shader/uniform.rs index 7281ef869d..eef0cc0953 100644 --- a/crates/bevy_render/src/shader/uniform.rs +++ b/crates/bevy_render/src/shader/uniform.rs @@ -71,6 +71,7 @@ impl ShaderDefSuffixProvider for bool { #[derive(Clone, Debug, Eq, PartialEq)] pub enum FieldBindType { Uniform { size: usize }, + Buffer, Texture, } @@ -82,11 +83,11 @@ pub struct FieldInfo { pub is_instanceable: bool, } -pub trait AsFieldBindType { +pub trait GetFieldBindType { fn get_bind_type(&self) -> Option; } -impl AsFieldBindType for ColorSource { +impl GetFieldBindType for ColorSource { fn get_bind_type(&self) -> Option { match *self { ColorSource::Texture(_) => Some(FieldBindType::Texture), @@ -95,7 +96,7 @@ impl AsFieldBindType for ColorSource { } } -impl AsFieldBindType for Option> { +impl GetFieldBindType for Option> { fn get_bind_type(&self) -> Option { match *self { Some(_) => Some(FieldBindType::Texture), @@ -104,13 +105,13 @@ impl AsFieldBindType for Option> { } } -impl AsFieldBindType for Handle { +impl GetFieldBindType for Handle { fn get_bind_type(&self) -> Option { Some(FieldBindType::Texture) } } -impl AsFieldBindType for T +impl GetFieldBindType for T where T: Bytes, { diff --git a/crates/bevy_render/src/shader/uniforms/local_to_world.rs b/crates/bevy_render/src/shader/uniforms/local_to_world.rs index 09c4ce485e..6b6c5605ac 100644 --- a/crates/bevy_render/src/shader/uniforms/local_to_world.rs +++ b/crates/bevy_render/src/shader/uniforms/local_to_world.rs @@ -1,6 +1,6 @@ use crate::{ pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat}, - shader::{AsFieldBindType, AsUniforms, FieldBindType, FieldInfo}, + shader::{GetFieldBindType, AsUniforms, FieldBindType, FieldInfo}, texture::Texture, }; use bevy_asset::Handle; diff --git a/crates/bevy_sprite/src/entity.rs b/crates/bevy_sprite/src/entity.rs index 6fe4698a8d..1c732dcd9b 100644 --- a/crates/bevy_sprite/src/entity.rs +++ b/crates/bevy_sprite/src/entity.rs @@ -1,10 +1,9 @@ use crate::{ - render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE, + render::SPRITE_PIPELINE_HANDLE, sprite::Sprite, ColorMaterial, Quad, QUAD_HANDLE, SpriteSheet, SPRITE_SHEET_PIPELINE_HANDLE, SpriteSheetSprite, }; use bevy_asset::Handle; use bevy_derive::EntityArchetype; use bevy_render::{mesh::Mesh, Renderable}; -use bevy_transform::prelude::*; #[derive(EntityArchetype)] pub struct SpriteEntity { @@ -32,13 +31,14 @@ impl Default for SpriteEntity { #[derive(EntityArchetype)] pub struct SpriteSheetEntity { - pub sprite: Sprite, + pub sprite: SpriteSheetSprite, pub sprite_sheet: Handle, pub renderable: Renderable, - pub local_to_world: LocalToWorld, - pub translation: Translation, - pub rotation: Rotation, - pub scale: Scale, + pub mesh: Handle, // TODO: maybe abstract this out + // pub local_to_world: LocalToWorld, + // pub translation: Translation, + // pub rotation: Rotation, + // pub scale: Scale, } impl Default for SpriteSheetEntity { @@ -50,10 +50,11 @@ impl Default for SpriteSheetEntity { pipelines: vec![SPRITE_SHEET_PIPELINE_HANDLE], ..Default::default() }, - local_to_world: Default::default(), - translation: Default::default(), - rotation: Default::default(), - scale: Default::default(), + mesh: QUAD_HANDLE, + // local_to_world: Default::default(), + // translation: Default::default(), + // rotation: Default::default(), + // scale: Default::default(), } } } diff --git a/crates/bevy_sprite/src/rect.rs b/crates/bevy_sprite/src/rect.rs index b32088d80b..b191677efd 100644 --- a/crates/bevy_sprite/src/rect.rs +++ b/crates/bevy_sprite/src/rect.rs @@ -1,3 +1,4 @@ +use bevy_core::bytes::Byteable; use glam::Vec2; /// A rectangle defined by two points. There is no defined origin, so 0,0 could be anywhere (top-left, bottom-left, etc) @@ -18,4 +19,6 @@ impl Rect { pub fn height(&self) -> f32 { self.max.y() - self.min.y() } -} \ No newline at end of file +} + +unsafe impl Byteable for Rect {} diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 5ecac686ff..e73e1414a2 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -1,4 +1,4 @@ -use crate::{ColorMaterial, Quad}; +use crate::{ColorMaterial, Quad, SpriteSheet, SpriteSheetSprite}; use bevy_asset::{Assets, Handle}; use bevy_render::{ base_render_graph, @@ -112,6 +112,8 @@ pub fn build_sprite_pipeline(shaders: &mut Assets) -> PipelineDescriptor pub mod node { pub const COLOR_MATERIAL: &'static str = "color_material"; pub const QUAD: &'static str = "quad"; + pub const SPRITE_SHEET: &'static str = "sprite_sheet"; + pub const SPRITE_SHEET_SPRITE: &'static str = "sprite_sheet_sprite"; } pub trait SpriteRenderGraphBuilder { @@ -131,6 +133,16 @@ impl SpriteRenderGraphBuilder for RenderGraph { self.add_node_edge(node::QUAD, base_render_graph::node::MAIN_PASS) .unwrap(); + self.add_system_node( + node::SPRITE_SHEET, + AssetUniformNode::::new(true), + ); + + self.add_system_node( + node::SPRITE_SHEET_SPRITE, + UniformNode::::new(true), + ); + let mut pipelines = resources.get_mut::>().unwrap(); let mut shaders = resources.get_mut::>().unwrap(); pipelines.set(SPRITE_PIPELINE_HANDLE, build_sprite_pipeline(&mut shaders)); diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index 41555db818..95c58ad67b 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -1,9 +1,22 @@ #version 450 -// sprite -layout(location = 0) in vec3 Sprite_Position; -// this is a vec2 instead of an int due to WebGPU limitations -layout(location = 1) in ivec2 Sprite_Index; +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; @@ -16,21 +29,19 @@ struct Rect { vec2 end; }; -layout(set = 1, binding = 0) buffer SpriteSheet { - Rect[] SpriteSheet_sprites; +layout(set = 1, binding = 0) buffer SpriteSheet_sprites { + Rect[] Sprites; }; -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) -); +layout(set = 2, binding = 0) uniform SpriteSheetSprite { + vec3 SpriteSheetSprite_position; + uint SpriteSheetSprite_index; +}; void main() { - Rect sprite_rect = SpriteSheet_sprites[Sprite_Index.x]; + Rect sprite_rect = Sprites[SpriteSheetSprite_index]; vec2 dimensions = sprite_rect.end - sprite_rect.begin; - vec2 vertex_position = positions[gl_VertexIndex] * dimensions; + vec2 vertex_position = Vertex_Position.xy * dimensions; vec2 uvs[4] = vec2[]( vec2(sprite_rect.end.x, sprite_rect.begin.y), sprite_rect.begin, @@ -38,5 +49,5 @@ void main() { vec2(sprite_rect.begin.x, sprite_rect.end.y) ); v_Uv = uvs[gl_VertexIndex]; - gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + Sprite_Position, 1.0); + gl_Position = ViewProj * vec4(vec3(vertex_position, 0.0) + SpriteSheetSprite_position, 1.0); } \ No newline at end of file diff --git a/crates/bevy_sprite/src/sprite_sheet.rs b/crates/bevy_sprite/src/sprite_sheet.rs index db04da8264..b957fbece8 100644 --- a/crates/bevy_sprite/src/sprite_sheet.rs +++ b/crates/bevy_sprite/src/sprite_sheet.rs @@ -1,29 +1,30 @@ use crate::Rect; use bevy_app::{Events, GetEventReader}; use bevy_asset::{AssetEvent, Assets, Handle}; -use bevy_derive::{Uniform, Bytes}; +use bevy_core::bytes::AsBytes; +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 glam::{Vec4, Vec3}; +#[derive(Uniforms)] pub struct SpriteSheet { pub texture: Handle, pub sprites: Vec, } -#[repr(C)] -#[derive(Uniform, Bytes)] +// 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 +#[derive(Uniform, Bytes, Default)] pub struct SpriteSheetSprite { - #[uniform(vertex)] - pub postition: Vec4, - #[uniform(vertex)] - pub index: u16, + pub position: Vec3, + pub index: u32, } pub const SPRITE_SHEET_BUFFER_ASSET_INDEX: usize = 0; @@ -69,20 +70,20 @@ pub fn sprite_sheet_resource_provider_system(resources: &mut Resources) -> Box() .add_asset_loader::(); } -} +} \ No newline at end of file