Skip to content

Commit

Permalink
Flip UI image (#6292)
Browse files Browse the repository at this point in the history
# Objective
Fixes  #3225, Allow for flippable UI Images

## Solution
Add flip_x and flip_y fields to UiImage, and swap the UV coordinates accordingly in ui_prepare_nodes.

## Changelog
* Changes UiImage to a struct with texture, flip_x, and flip_y fields.
* Adds flip_x and flip_y fields to ExtractedUiNode.
* Changes extract_uinodes to extract the flip_x and flip_y values from UiImage.
* Changes prepare_uinodes to swap the UV coordinates as required.
* Changes UiImage derefs to texture field accesses.
  • Loading branch information
ickshonpe committed Nov 14, 2022
1 parent 3ac06b5 commit 5f12611
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 18 deletions.
23 changes: 17 additions & 6 deletions crates/bevy_ui/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ pub struct ExtractedUiNode {
pub image: Handle<Image>,
pub atlas_size: Option<Vec2>,
pub clip: Option<Rect>,
pub flip_x: bool,
pub flip_y: bool,
pub scale_factor: f32,
}

Expand Down Expand Up @@ -225,13 +227,11 @@ pub fn extract_uinodes(
if !visibility.is_visible() {
continue;
}

let image = if let Some(image) = maybe_image {
image.0.clone_weak()
let (image, flip_x, flip_y) = if let Some(image) = maybe_image {
(image.texture.clone_weak(), image.flip_x, image.flip_y)
} else {
DEFAULT_IMAGE_HANDLE.typed().clone_weak()
(DEFAULT_IMAGE_HANDLE.typed().clone_weak(), false, false)
};

// Skip loading images
if !images.contains(&image) {
continue;
Expand All @@ -252,6 +252,8 @@ pub fn extract_uinodes(
image,
atlas_size: None,
clip: clip.map(|clip| clip.clip),
flip_x,
flip_y,
scale_factor,
});
}
Expand Down Expand Up @@ -378,6 +380,8 @@ pub fn extract_text_uinodes(
image: texture,
atlas_size,
clip: clip.map(|clip| clip.clip),
flip_x: false,
flip_y: false,
scale_factor,
});
}
Expand Down Expand Up @@ -512,7 +516,7 @@ pub fn prepare_uinodes(
}

let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max);
let uvs = [
let mut uvs = [
Vec2::new(
uinode_rect.min.x + positions_diff[0].x * extracted_uinode.scale_factor,
uinode_rect.min.y + positions_diff[0].y * extracted_uinode.scale_factor,
Expand All @@ -532,6 +536,13 @@ pub fn prepare_uinodes(
]
.map(|pos| pos / atlas_extent);

if extracted_uinode.flip_x {
uvs = [uvs[1], uvs[0], uvs[3], uvs[2]];
}
if extracted_uinode.flip_y {
uvs = [uvs[3], uvs[2], uvs[1], uvs[0]];
}

for i in QUAD_INDICES {
ui_meta.vertices.push(UiVertex {
position: positions_clipped[i].into(),
Expand Down
33 changes: 26 additions & 7 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{Size, UiRect};
use bevy_asset::Handle;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
use bevy_math::{Rect, Vec2};
use bevy_reflect::prelude::*;
Expand Down Expand Up @@ -452,19 +451,39 @@ impl From<Color> for BackgroundColor {
}

/// The 2D texture displayed for this UI node
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[derive(Component, Clone, Debug, Reflect)]
#[reflect(Component, Default)]
pub struct UiImage(pub Handle<Image>);
pub struct UiImage {
/// Handle to the texture
pub texture: Handle<Image>,
/// Whether the image should be flipped along its x-axis
pub flip_x: bool,
/// Whether the image should be flipped along its y-axis
pub flip_y: bool,
}

impl Default for UiImage {
fn default() -> Self {
Self(DEFAULT_IMAGE_HANDLE.typed())
fn default() -> UiImage {
UiImage {
texture: DEFAULT_IMAGE_HANDLE.typed(),
flip_x: false,
flip_y: false,
}
}
}

impl UiImage {
pub fn new(texture: Handle<Image>) -> Self {
Self {
texture,
..Default::default()
}
}
}

impl From<Handle<Image>> for UiImage {
fn from(handle: Handle<Image>) -> Self {
Self(handle)
fn from(texture: Handle<Image>) -> Self {
Self::new(texture)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui/src/widget/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn image_node_system(
mut query: Query<(&mut CalculatedSize, &UiImage), (With<ImageMode>, Without<Text>)>,
) {
for (mut calculated_size, image) in &mut query {
if let Some(texture) = textures.get(image) {
if let Some(texture) = textures.get(&image.texture) {
let size = Size {
width: Val::Px(texture.texture_descriptor.size.width as f32),
height: Val::Px(texture.texture_descriptor.size.height as f32),
Expand Down
8 changes: 4 additions & 4 deletions examples/games/game_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ mod splash {
size: Size::new(Val::Px(200.0), Val::Auto),
..default()
},
image: UiImage(icon),
image: UiImage::new(icon),
..default()
},
OnSplashScreen,
Expand Down Expand Up @@ -462,7 +462,7 @@ mod menu {
let icon = asset_server.load("textures/Game Icons/right.png");
parent.spawn(ImageBundle {
style: button_icon_style.clone(),
image: UiImage(icon),
image: UiImage::new(icon),
..default()
});
parent.spawn(TextBundle::from_section(
Expand All @@ -483,7 +483,7 @@ mod menu {
let icon = asset_server.load("textures/Game Icons/wrench.png");
parent.spawn(ImageBundle {
style: button_icon_style.clone(),
image: UiImage(icon),
image: UiImage::new(icon),
..default()
});
parent.spawn(TextBundle::from_section(
Expand All @@ -504,7 +504,7 @@ mod menu {
let icon = asset_server.load("textures/Game Icons/exitRight.png");
parent.spawn(ImageBundle {
style: button_icon_style,
image: UiImage(icon),
image: UiImage::new(icon),
..default()
});
parent.spawn(TextBundle::from_section("Quit", button_text_style));
Expand Down

0 comments on commit 5f12611

Please sign in to comment.