diff --git a/crates/bevy_core/src/bytes.rs b/crates/bevy_core/src/bytes.rs index cf6f43a55b..555f314bc7 100644 --- a/crates/bevy_core/src/bytes.rs +++ b/crates/bevy_core/src/bytes.rs @@ -91,58 +91,11 @@ unsafe impl Byteable for i64 {} unsafe impl Byteable for isize {} unsafe impl Byteable for f32 {} unsafe impl Byteable for f64 {} - -impl Bytes for Vec2 { - fn write_bytes(&self, buffer: &mut [u8]) { - let array: [f32; 2] = (*self).into(); - array.write_bytes(buffer); - } - fn byte_len(&self) -> usize { - std::mem::size_of::() - } -} - -impl FromBytes for Vec2 { - fn from_bytes(bytes: &[u8]) -> Self { - let array = <[f32; 2]>::from_bytes(bytes); - Vec2::from(array) - } -} - -impl Bytes for Vec3 { - fn write_bytes(&self, buffer: &mut [u8]) { - let array: [f32; 3] = (*self).into(); - array.write_bytes(buffer); - } - fn byte_len(&self) -> usize { - // cant use self here because Vec3 is a simd type / technically a vec4 - std::mem::size_of::<[f32; 3]>() - } -} - -impl FromBytes for Vec3 { - fn from_bytes(bytes: &[u8]) -> Self { - let array = <[f32; 3]>::from_bytes(bytes); - Vec3::from(array) - } -} - -impl Bytes for Vec4 { - fn write_bytes(&self, buffer: &mut [u8]) { - let array: [f32; 4] = (*self).into(); - array.write_bytes(buffer); - } - fn byte_len(&self) -> usize { - std::mem::size_of::() - } -} - -impl FromBytes for Vec4 { - fn from_bytes(bytes: &[u8]) -> Self { - let array = <[f32; 4]>::from_bytes(bytes); - Vec4::from(array) - } -} +unsafe impl Byteable for Vec2 {} +// NOTE: Vec3 actually takes up the size of 4 floats / 16 bytes due to SIMD. This is actually convenient because GLSL +// uniform buffer objects pad Vec3s to be 16 bytes. +unsafe impl Byteable for Vec3 {} +unsafe impl Byteable for Vec4 {} impl Bytes for Mat4 { fn write_bytes(&self, buffer: &mut [u8]) { diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index d5d1ce493b..524a260e2f 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -25,7 +25,7 @@ impl AppPlugin for PbrPlugin { .register_component::() .add_system_to_stage( stage::POST_UPDATE, - shader::asset_shader_def_system::.system(), + shader::asset_shader_defs_system::.system(), ); let resources = app.resources(); let mut render_graph = resources.get_mut::().unwrap(); diff --git a/crates/bevy_render/src/draw.rs b/crates/bevy_render/src/draw.rs index 4fa3093249..635cc2d48a 100644 --- a/crates/bevy_render/src/draw.rs +++ b/crates/bevy_render/src/draw.rs @@ -219,6 +219,7 @@ impl<'a> DrawContext<'a> { specialization, ) }; + draw.set_pipeline(specialized_pipeline); self.current_pipeline = Some(specialized_pipeline); Ok(()) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 1a35646bba..c65801521b 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -41,6 +41,7 @@ use mesh::mesh_resource_provider_system; use pipeline::{draw_render_pipelines_system, RenderPipelines}; use render_graph::{system::render_graph_schedule_executor_system, RenderGraph}; use render_resource::AssetRenderResourceBindings; +use shader::clear_shader_defs_system; use std::ops::Range; use texture::{PngTextureLoader, TextureResourceSystemState}; @@ -112,7 +113,8 @@ impl AppPlugin for RenderPlugin { stage::RENDER_GRAPH_SYSTEMS, render_graph_schedule_executor_system, ) - .add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system()); + .add_system_to_stage(stage::DRAW, draw_render_pipelines_system.system()) + .add_system_to_stage(stage::POST_RENDER, clear_shader_defs_system.system()); if let Some(ref config) = self.base_render_graph_config { let resources = app.resources(); diff --git a/crates/bevy_render/src/pipeline/pipeline_layout.rs b/crates/bevy_render/src/pipeline/pipeline_layout.rs index b3b98a8f68..a80b2f8983 100644 --- a/crates/bevy_render/src/pipeline/pipeline_layout.rs +++ b/crates/bevy_render/src/pipeline/pipeline_layout.rs @@ -14,7 +14,7 @@ impl PipelineLayout { .iter() .find(|bind_group| bind_group.index == index) } - + pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self { let mut bind_groups = HashMap::::new(); let mut vertex_buffer_descriptors = Vec::new(); diff --git a/crates/bevy_render/src/shader/shader_defs.rs b/crates/bevy_render/src/shader/shader_defs.rs index 8252455d96..4fb2439246 100644 --- a/crates/bevy_render/src/shader/shader_defs.rs +++ b/crates/bevy_render/src/shader/shader_defs.rs @@ -55,7 +55,7 @@ impl ShaderDef for Option> { } } -pub fn shader_def_system(shader_defs: Com, mut render_pipelines: ComMut) +pub fn shader_defs_system(shader_defs: Com, mut render_pipelines: ComMut) where T: ShaderDefs + Send + Sync + 'static, { @@ -70,7 +70,17 @@ where } } -pub fn asset_shader_def_system( +pub fn clear_shader_defs_system(mut render_pipelines: ComMut) { + for render_pipeline in render_pipelines.pipelines.iter_mut() { + render_pipeline + .specialization + .shader_specialization + .shader_defs + .clear(); + } +} + +pub fn asset_shader_defs_system( assets: Res>, asset_handle: Com>, mut render_pipelines: ComMut, diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index ac91837762..a2ce159023 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -22,7 +22,7 @@ use bevy_asset::{AddAsset, Assets, Handle}; use bevy_render::{ mesh::{shape, Mesh}, render_graph::RenderGraph, - shader::asset_shader_def_system, + shader::asset_shader_defs_system, }; use glam::Vec2; use legion::prelude::IntoSystem; @@ -40,7 +40,7 @@ impl AppPlugin for SpritePlugin { .add_system_to_stage(stage::POST_UPDATE, sprite_system()) .add_system_to_stage( stage::POST_UPDATE, - asset_shader_def_system::.system(), + asset_shader_defs_system::.system(), ); let resources = app.resources(); diff --git a/crates/bevy_sprite/src/render/sprite_sheet.frag b/crates/bevy_sprite/src/render/sprite_sheet.frag index d2bcdbe6e4..8c8d9217f0 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.frag +++ b/crates/bevy_sprite/src/render/sprite_sheet.frag @@ -1,6 +1,7 @@ #version 450 layout(location = 0) in vec2 v_Uv; +layout(location = 1) in vec4 v_Color; layout(location = 0) out vec4 o_Target; @@ -8,7 +9,7 @@ layout(set = 1, binding = 2) uniform texture2D TextureAtlas_texture; layout(set = 1, binding = 3) uniform sampler TextureAtlas_texture_sampler; void main() { - o_Target = texture( + o_Target = v_Color * texture( sampler2D(TextureAtlas_texture, TextureAtlas_texture_sampler), v_Uv); } diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index 0449f9abf4..f3ec814894 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -5,6 +5,7 @@ layout(location = 1) in vec3 Vertex_Normal; layout(location = 2) in vec2 Vertex_Uv; layout(location = 0) out vec2 v_Uv; +layout(location = 1) out vec4 v_Color; // TODO: remove UI shader def and replace with generic "Camera" when its easier to manually bind global RenderResourceBindings #ifdef UI_CAMERA @@ -34,6 +35,7 @@ layout(set = 1, binding = 1) buffer TextureAtlas_textures { layout(set = 2, binding = 0) uniform TextureAtlasSprite { vec3 TextureAtlasSprite_position; + vec4 TextureAtlasSprite_color; float TextureAtlasSprite_scale; uint TextureAtlasSprite_index; }; @@ -41,7 +43,7 @@ layout(set = 2, binding = 0) uniform TextureAtlasSprite { void main() { Rect sprite_rect = Textures[TextureAtlasSprite_index]; vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin; - vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position; + vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions * TextureAtlasSprite_scale, 0.0) + TextureAtlasSprite_position.xyz; vec2 uvs[4] = vec2[]( vec2(sprite_rect.begin.x, sprite_rect.end.y), sprite_rect.begin, @@ -49,5 +51,6 @@ void main() { sprite_rect.end ); v_Uv = uvs[gl_VertexIndex] / AtlasSize; + v_Color = TextureAtlasSprite_color; gl_Position = ViewProj * vec4(vertex_position, 1.0); } \ No newline at end of file diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index 2989e9d21c..5a52a6c4d2 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -4,6 +4,7 @@ use bevy_core::bytes::Bytes; use bevy_render::{ render_resource::{RenderResource, RenderResources}, texture::Texture, + Color, }; use glam::{Vec2, Vec3}; use std::collections::HashMap; @@ -21,14 +22,26 @@ pub struct TextureAtlas { // 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(Bytes, RenderResources, RenderResource, Default)] +#[derive(Bytes, RenderResources, RenderResource)] #[render_resources(from_self)] pub struct TextureAtlasSprite { pub position: Vec3, + pub color: Color, pub scale: f32, pub index: u32, } +impl Default for TextureAtlasSprite { + fn default() -> Self { + Self { + index: 0, + color: Color::WHITE, + scale: 1.0, + position: Default::default(), + } + } +} + impl TextureAtlas { pub fn new_empty(texture: Handle, dimensions: Vec2) -> Self { Self { @@ -81,3 +94,36 @@ impl TextureAtlas { .and_then(|texture_handles| texture_handles.get(&texture).cloned()) } } + +#[cfg(test)] +mod tests { + use crate::TextureAtlasSprite; + use bevy_core::bytes::{Bytes, FromBytes}; + use bevy_render::Color; + use glam::Vec3; + + #[test] + fn test_atlas_byte_conversion() { + let x = TextureAtlasSprite { + color: Color::RED, + index: 2, + position: Vec3::new(1., 2., 3.), + scale: 4.0, + }; + + assert_eq!(x.byte_len(), 36); + let mut bytes = vec![0; x.byte_len()]; + + x.write_bytes(&mut bytes); + + let position = Vec3::from_bytes(&bytes[0..12]); + let color = Color::from_bytes(&bytes[12..28]); + let scale = f32::from_bytes(&bytes[28..32]); + let index = u32::from_bytes(&bytes[32..36]); + + assert_eq!(position, x.position); + assert_eq!(color, x.color); + assert_eq!(scale, x.scale); + assert_eq!(index, x.index); + } +} diff --git a/crates/bevy_text/src/draw.rs b/crates/bevy_text/src/draw.rs index cdcff02317..5ad6dc589d 100644 --- a/crates/bevy_text/src/draw.rs +++ b/crates/bevy_text/src/draw.rs @@ -132,6 +132,7 @@ impl<'a> Drawable for DrawableText<'a> { let offset = scaled_font.descent() + glyph_height; let sprite_buffer = TextureAtlasSprite { index: glyph_atlas_info.char_index, + color: self.style.color, position: caret + Vec3::new( 0.0 + glyph_width / 2.0 + bounds.min.x, diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs index ae49ac354b..884ad9506c 100644 --- a/examples/2d/sprite_sheet.rs +++ b/examples/2d/sprite_sheet.rs @@ -42,9 +42,8 @@ fn setup( .add_entity(SpriteSheetEntity { texture_atlas: texture_atlas_handle, sprite: TextureAtlasSprite { - index: 0, scale: 6.0, - position: Vec3::new(0.0, 0.0, 0.0), + ..Default::default() }, ..Default::default() }) diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index d7f0a830ea..c5d0fc41db 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -8,7 +8,7 @@ fn main() { .add_startup_system(setup.system()) .add_system_to_stage( stage::POST_UPDATE, - shader::asset_shader_def_system::.system(), + shader::asset_shader_defs_system::.system(), ) .run(); }