From 240008880ccac84fc82495492bb5707641c0a6bf Mon Sep 17 00:00:00 2001 From: Zicklag Date: Fri, 5 Feb 2021 17:02:21 -0600 Subject: [PATCH] Add Sprite Flipping --- Cargo.toml | 4 +++ crates/bevy_sprite/src/lib.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 2 +- crates/bevy_sprite/src/render/sprite.vert | 18 +++++++++- .../bevy_sprite/src/render/sprite_sheet.vert | 32 +++++++++++++---- crates/bevy_sprite/src/sprite.rs | 34 ++++++++++++++++++- crates/bevy_sprite/src/texture_atlas.rs | 5 +-- crates/bevy_text/src/draw.rs | 1 + examples/2d/contributors.rs | 1 + examples/2d/sprite_flipping.rs | 27 +++++++++++++++ 10 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 examples/2d/sprite_flipping.rs diff --git a/Cargo.toml b/Cargo.toml index fa0cbd53498ac7..381b626215379a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,10 @@ path = "examples/hello_world.rs" name = "sprite" path = "examples/2d/sprite.rs" +[[example]] +name = "sprite_flipping" +path = "examples/2d/sprite_flipping.rs" + [[example]] name = "sprite_sheet" path = "examples/2d/sprite_sheet.rs" diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index bc574243a4bf56..b0969789850253 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -21,7 +21,7 @@ pub use texture_atlas_builder::*; pub mod prelude { pub use crate::{ entity::{SpriteBundle, SpriteSheetBundle}, - ColorMaterial, Sprite, SpriteResizeMode, TextureAtlas, TextureAtlasSprite, + ColorMaterial, Sprite, SpriteFlip, SpriteResizeMode, TextureAtlas, TextureAtlasSprite, }; } diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 1f4c2005ed8f1b..f0a73d804e8839 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -109,7 +109,7 @@ pub fn build_sprite_pipeline(shaders: &mut Assets) -> PipelineDescriptor topology: PrimitiveTopology::TriangleList, strip_index_format: None, front_face: FrontFace::Ccw, - cull_mode: CullMode::None, + cull_mode: CullMode::Back, polygon_mode: PolygonMode::Fill, }, ..PipelineDescriptor::new(ShaderStages { diff --git a/crates/bevy_sprite/src/render/sprite.vert b/crates/bevy_sprite/src/render/sprite.vert index fe1619d14b7fc7..faab3fd53040e5 100644 --- a/crates/bevy_sprite/src/render/sprite.vert +++ b/crates/bevy_sprite/src/render/sprite.vert @@ -16,9 +16,25 @@ layout(set = 2, binding = 0) uniform Transform { layout(set = 2, binding = 1) uniform Sprite_size { vec2 size; }; +layout(set = 2, binding = 2) uniform Sprite_flip { + uint flip; +}; void main() { - v_Uv = Vertex_Uv; + vec2 uv = Vertex_Uv; + + // Flip the sprite if necessary + uint x_flip_bit = 1; + uint y_flip_bit = 2; + if ((flip & x_flip_bit) == x_flip_bit) { + uv = vec2(1.0 - uv.x , uv.y); + } + if ((flip & y_flip_bit) == y_flip_bit) { + uv = vec2(uv.x, 1.0 - uv.y); + } + + v_Uv = uv; + vec3 position = Vertex_Position * vec3(size, 1.0); gl_Position = ViewProj * Model * vec4(position, 1.0); } \ No newline at end of file diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index e16012abef6fd2..90f384c0a84bfd 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -30,13 +30,18 @@ layout(set = 2, binding = 0) uniform Transform { mat4 SpriteTransform; }; -layout(set = 2, binding = 1) uniform TextureAtlasSprite { - vec4 TextureAtlasSprite_color; - uint TextureAtlasSprite_index; +layout(set = 2, binding = 1) uniform TextureAtlasSprite_color { + vec4 color; +}; +layout(set = 2, binding = 2) uniform TextureAtlasSprite_index { + uint index; +}; +layout(set = 2, binding = 3) uniform TextureAtlasSprite_flip { + uint flip; }; void main() { - Rect sprite_rect = Textures[TextureAtlasSprite_index]; + Rect sprite_rect = Textures[index]; vec2 sprite_dimensions = sprite_rect.end - sprite_rect.begin; vec3 vertex_position = vec3(Vertex_Position.xy * sprite_dimensions, 0.0); vec2 atlas_positions[4] = vec2[]( @@ -45,7 +50,22 @@ void main() { vec2(sprite_rect.end.x, sprite_rect.begin.y), sprite_rect.end ); - v_Uv = (atlas_positions[gl_VertexIndex]) / AtlasSize; - v_Color = TextureAtlasSprite_color; + + vec2 uv = (atlas_positions[gl_VertexIndex]) / AtlasSize; + + // Flip the sprite if necessary + uint x_flip_bit = 1; + uint y_flip_bit = 2; + + if ((flip & x_flip_bit) == x_flip_bit) { + uv = vec2(1.0 - uv.x , uv.y); + } + if ((flip & y_flip_bit) == y_flip_bit) { + uv = vec2(uv.x, 1.0 - uv.y); + } + + v_Uv = uv; + + v_Color = color; gl_Position = ViewProj * SpriteTransform * 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 f35f712f252257..92fc3cfd6917ca 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -1,19 +1,50 @@ use crate::ColorMaterial; use bevy_asset::{Assets, Handle}; +use bevy_core::Bytes; use bevy_ecs::{Query, Res}; use bevy_math::Vec2; use bevy_reflect::{Reflect, ReflectDeserialize, TypeUuid}; -use bevy_render::{renderer::RenderResources, texture::Texture}; +use bevy_render::{ + renderer::{RenderResource, RenderResourceType, RenderResources}, + texture::Texture, +}; use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone, RenderResources, TypeUuid, Reflect)] #[uuid = "7233c597-ccfa-411f-bd59-9af349432ada"] pub struct Sprite { pub size: Vec2, + pub flip: SpriteFlip, #[render_resources(ignore)] pub resize_mode: SpriteResizeMode, } +/// Indicates how to flip the sprite +#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] +pub struct SpriteFlip { + pub x: bool, + pub y: bool, +} + +impl RenderResource for SpriteFlip { + fn resource_type(&self) -> Option { + Some(RenderResourceType::Buffer) + } + + fn write_buffer_bytes(&self, buffer: &mut [u8]) { + // First bit means flip x, second bit means flip y + (if self.x { 0b01 } else { 0 } | if self.y { 0b10 } else { 0 } as u32).write_bytes(buffer); + } + + fn buffer_byte_len(&self) -> Option { + Some(4) + } + + fn texture(&self) -> Option<&Handle> { + None + } +} + /// Determines how `Sprite` resize should be handled #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] #[reflect_value(PartialEq, Serialize, Deserialize)] @@ -34,6 +65,7 @@ impl Sprite { Self { size, resize_mode: SpriteResizeMode::Manual, + flip: SpriteFlip::default(), } } } diff --git a/crates/bevy_sprite/src/texture_atlas.rs b/crates/bevy_sprite/src/texture_atlas.rs index aa525bd71fe622..7db520227af561 100644 --- a/crates/bevy_sprite/src/texture_atlas.rs +++ b/crates/bevy_sprite/src/texture_atlas.rs @@ -1,4 +1,4 @@ -use crate::Rect; +use crate::{Rect, SpriteFlip}; use bevy_asset::Handle; use bevy_core::Byteable; use bevy_math::Vec2; @@ -26,10 +26,10 @@ pub struct TextureAtlas { } #[derive(Debug, RenderResources, RenderResource, Clone)] -#[render_resources(from_self)] pub struct TextureAtlasSprite { pub color: Color, pub index: u32, + pub flip: SpriteFlip, } impl Default for TextureAtlasSprite { @@ -37,6 +37,7 @@ impl Default for TextureAtlasSprite { Self { index: 0, color: Color::WHITE, + flip: Default::default(), } } } diff --git a/crates/bevy_text/src/draw.rs b/crates/bevy_text/src/draw.rs index 3a00d7bda02ad5..bae1272fdef9a8 100644 --- a/crates/bevy_text/src/draw.rs +++ b/crates/bevy_text/src/draw.rs @@ -71,6 +71,7 @@ impl<'a> Drawable for DrawableText<'a> { let sprite = TextureAtlasSprite { index: tv.atlas_info.glyph_index, color: self.sections[tv.section_index].style.color, + flip: Default::default(), }; // To get the rendering right for non-one scaling factors, we need diff --git a/examples/2d/contributors.rs b/examples/2d/contributors.rs index 821196b9c1c8b8..041feff06ef10f 100644 --- a/examples/2d/contributors.rs +++ b/examples/2d/contributors.rs @@ -87,6 +87,7 @@ fn setup( sprite: Sprite { size: Vec2::new(1.0, 1.0) * SPRITE_SIZE, resize_mode: SpriteResizeMode::Manual, + ..Default::default() }, material: materials.add(ColorMaterial { color: COL_DESELECTED * col, diff --git a/examples/2d/sprite_flipping.rs b/examples/2d/sprite_flipping.rs new file mode 100644 index 00000000000000..a661172d05d70a --- /dev/null +++ b/examples/2d/sprite_flipping.rs @@ -0,0 +1,27 @@ +use bevy::prelude::*; + +fn main() { + App::build() + .add_plugins(DefaultPlugins) + .add_startup_system(setup.system()) + .run(); +} + +fn setup( + commands: &mut Commands, + asset_server: Res, + mut materials: ResMut>, +) { + let texture_handle = asset_server.load("branding/icon.png"); + commands + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(SpriteBundle { + material: materials.add(texture_handle.into()), + sprite: Sprite { + // Flip the logo to the left + flip: SpriteFlip { x: true, y: false }, + ..Default::default() + }, + ..Default::default() + }); +}