Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions crates/bevy_render/src/texture/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,38 @@ impl Image {
image
}

/// A transparent white 1x1x1 image.
///
/// Contrast to [`Image::default`], which is opaque.
pub fn transparent() -> Image {
// We rely on the default texture format being RGBA8UnormSrgb
// when constructing a transparent color from bytes.
// If this changes, this function will need to be updated.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will we find out? Will it fail to compile?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will panic when the examples are run :)

let format = TextureFormat::bevy_default();
debug_assert!(format.pixel_size() == 4);
let data = vec![255, 255, 255, 0];
Image {
data,
texture_descriptor: wgpu::TextureDescriptor {
size: Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
format,
dimension: TextureDimension::D2,
label: None,
mip_level_count: 1,
sample_count: 1,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
},
sampler: ImageSampler::Default,
texture_view_descriptor: None,
asset_usage: RenderAssetUsages::default(),
}
}

/// Creates a new image from raw binary data and the corresponding metadata, by filling
/// the image data with the `pixel` data repeated multiple times.
///
Expand Down
16 changes: 13 additions & 3 deletions crates/bevy_render/src/texture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ use bevy_app::{App, Plugin};
use bevy_asset::{AssetApp, Assets, Handle};
use bevy_ecs::prelude::*;

/// A handle to a 1 x 1 transparent white image.
///
/// Like [`Handle<Image>::default`], this is a handle to a fallback image asset.
/// While that handle points to an opaque white 1 x 1 image, this handle points to a transparent 1 x 1 white image.
// Number randomly selected by fair WolframAlpha query. Totally arbitrary.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better than a fair dice roll (xkcd)!

pub const TRANSPARENT_IMAGE_HANDLE: Handle<Image> =
Handle::weak_from_u128(154728948001857810431816125397303024160);

// TODO: replace Texture names with Image names?
/// Adds the [`Image`] as an asset and makes sure that they are extracted and prepared for the GPU.
pub struct ImagePlugin {
Expand Down Expand Up @@ -89,9 +97,11 @@ impl Plugin for ImagePlugin {
.init_asset::<Image>()
.register_asset_reflect::<Image>();

app.world_mut()
.resource_mut::<Assets<Image>>()
.insert(&Handle::default(), Image::default());
let mut image_assets = app.world_mut().resource_mut::<Assets<Image>>();

image_assets.insert(&Handle::default(), Image::default());
image_assets.insert(&TRANSPARENT_IMAGE_HANDLE, Image::transparent());

#[cfg(feature = "basis-universal")]
if let Some(processor) = app
.world()
Expand Down
60 changes: 12 additions & 48 deletions crates/bevy_ui/src/node_bundles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use bevy_transform::prelude::{GlobalTransform, Transform};
/// Contains the [`Node`] component and other components required to make a container.
///
/// See [`node_bundles`](crate::node_bundles) for more specialized bundles like [`TextBundle`].
#[derive(Bundle, Clone, Debug)]
#[derive(Bundle, Clone, Debug, Default)]
pub struct NodeBundle {
/// Describes the logical size of the node
pub node: Node,
Expand Down Expand Up @@ -58,26 +58,6 @@ pub struct NodeBundle {
pub z_index: ZIndex,
}

impl Default for NodeBundle {
fn default() -> Self {
NodeBundle {
// Transparent background
background_color: Color::NONE.into(),
border_color: Color::NONE.into(),
border_radius: BorderRadius::default(),
node: Default::default(),
style: Default::default(),
focus_policy: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
inherited_visibility: Default::default(),
view_visibility: Default::default(),
z_index: Default::default(),
}
}
}

/// A UI node that is an image
///
/// # Extra behaviours
Expand All @@ -94,8 +74,12 @@ pub struct ImageBundle {
pub style: Style,
/// The calculated size based on the given image
pub calculated_size: ContentSize,
/// The image of the node
/// The image of the node.
///
/// To tint the image, change the `color` field of this component.
pub image: UiImage,
/// The color of the background that will fill the containing node.
pub background_color: BackgroundColor,
/// The size of the image in pixels
///
/// This component is set automatically
Expand Down Expand Up @@ -176,7 +160,7 @@ pub struct AtlasImageBundle {
///
/// The positioning of this node is controlled by the UI layout system. If you need manual control,
/// use [`Text2dBundle`](bevy_text::Text2dBundle).
#[derive(Bundle, Debug)]
#[derive(Bundle, Debug, Default)]
pub struct TextBundle {
/// Describes the logical size of the node
pub node: Node,
Expand Down Expand Up @@ -214,29 +198,6 @@ pub struct TextBundle {
pub background_color: BackgroundColor,
}

#[cfg(feature = "bevy_text")]
impl Default for TextBundle {
fn default() -> Self {
Self {
text: Default::default(),
text_layout_info: Default::default(),
text_flags: Default::default(),
calculated_size: Default::default(),
node: Default::default(),
style: Default::default(),
focus_policy: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
inherited_visibility: Default::default(),
view_visibility: Default::default(),
z_index: Default::default(),
// Transparent background
background_color: BackgroundColor(Color::NONE),
}
}
}

#[cfg(feature = "bevy_text")]
impl TextBundle {
/// Create a [`TextBundle`] from a single section.
Expand Down Expand Up @@ -321,6 +282,8 @@ pub struct ButtonBundle {
pub border_radius: BorderRadius,
/// The image of the node
pub image: UiImage,
/// The background color that will fill the containing node
pub background_color: BackgroundColor,
/// The transform of the node
///
/// This component is automatically managed by the UI layout system.
Expand Down Expand Up @@ -348,9 +311,10 @@ impl Default for ButtonBundle {
style: Default::default(),
interaction: Default::default(),
focus_policy: FocusPolicy::Block,
border_color: BorderColor(Color::NONE),
border_radius: BorderRadius::default(),
border_color: Default::default(),
border_radius: Default::default(),
image: Default::default(),
background_color: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
Expand Down
54 changes: 48 additions & 6 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy_math::{Rect, Vec2};
use bevy_reflect::prelude::*;
use bevy_render::{
camera::{Camera, RenderTarget},
texture::Image,
texture::{Image, TRANSPARENT_IMAGE_HANDLE},
};
use bevy_transform::prelude::GlobalTransform;
use bevy_utils::warn_once;
Expand Down Expand Up @@ -1693,7 +1693,8 @@ pub enum GridPlacementError {
pub struct BackgroundColor(pub Color);

impl BackgroundColor {
pub const DEFAULT: Self = Self(Color::WHITE);
/// Background color is transparent by default.
pub const DEFAULT: Self = Self(Color::NONE);
}

impl Default for BackgroundColor {
Expand Down Expand Up @@ -1725,7 +1726,8 @@ impl<T: Into<Color>> From<T> for BorderColor {
}

impl BorderColor {
pub const DEFAULT: Self = BorderColor(Color::WHITE);
/// Border color is transparent by default.
pub const DEFAULT: Self = BorderColor(Color::NONE);
}

impl Default for BorderColor {
Expand Down Expand Up @@ -1819,27 +1821,67 @@ impl Outline {
}

/// The 2D texture displayed for this UI node
#[derive(Component, Clone, Debug, Reflect, Default)]
#[derive(Component, Clone, Debug, Reflect)]
#[reflect(Component, Default)]
pub struct UiImage {
/// The tint color used to draw the image
/// The tint color used to draw the image.
///
/// This is multiplied by the color of each pixel in the image.
/// The field value defaults to solid white, which will pass the image through unmodified.
pub color: Color,
/// Handle to the texture
/// Handle to the texture.
///
/// This defaults to a [`TRANSPARENT_IMAGE_HANDLE`], which points to a fully transparent 1x1 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 {
/// A transparent 1x1 image with a solid white tint.
///
/// # Warning
///
/// This will be invisible by default.
/// To set this to a visible image, you need to set the `texture` field to a valid image handle,
/// or use [`Handle<Image>`]'s default 1x1 solid white texture (as is done in [`UiImage::solid_color`]).
fn default() -> Self {
UiImage {
// This should be white because the tint is multiplied with the image,
// so if you set an actual image with default tint you'd want its original colors
color: Color::WHITE,
// This texture needs to be transparent by default, to avoid covering the background color
texture: TRANSPARENT_IMAGE_HANDLE,
flip_x: false,
flip_y: false,
}
}
}

impl UiImage {
/// Create a new [`UiImage`] with the given texture.
pub fn new(texture: Handle<Image>) -> Self {
Self {
texture,
color: Color::WHITE,
..Default::default()
}
}

/// Create a solid color [`UiImage`].
///
/// This is primarily useful for debugging / mocking the extents of your image.
pub fn solid_color(color: Color) -> Self {
Self {
texture: Handle::default(),
color,
flip_x: false,
flip_y: false,
}
}

/// Set the color tint
#[must_use]
pub const fn with_color(mut self, color: Color) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/color_grading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ fn add_button_for_value(
},
border_color: BorderColor(Color::WHITE),
border_radius: BorderRadius::MAX,
image: UiImage::default().with_color(Color::BLACK),
background_color: Color::BLACK.into(),
..default()
})
.insert(ColorGradingOptionWidget {
Expand Down
2 changes: 1 addition & 1 deletion examples/3d/split_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn setup(
..default()
},
border_color: Color::WHITE.into(),
image: UiImage::default().with_color(Color::srgb(0.25, 0.25, 0.25)),
background_color: Color::srgb(0.25, 0.25, 0.25).into(),
..default()
},
))
Expand Down
16 changes: 8 additions & 8 deletions examples/games/game_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style.clone(),
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
MenuButtonAction::Play,
Expand All @@ -477,7 +477,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style.clone(),
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
MenuButtonAction::Settings,
Expand All @@ -498,7 +498,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style,
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
MenuButtonAction::Quit,
Expand Down Expand Up @@ -567,7 +567,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style.clone(),
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
action,
Expand Down Expand Up @@ -654,7 +654,7 @@ mod menu {
height: Val::Px(65.0),
..button_style.clone()
},
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
quality_setting,
Expand All @@ -675,7 +675,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style,
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
MenuButtonAction::BackToSettings,
Expand Down Expand Up @@ -750,7 +750,7 @@ mod menu {
height: Val::Px(65.0),
..button_style.clone()
},
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
Volume(volume_setting),
Expand All @@ -764,7 +764,7 @@ mod menu {
.spawn((
ButtonBundle {
style: button_style,
image: UiImage::default().with_color(NORMAL_BUTTON),
background_color: NORMAL_BUTTON.into(),
..default()
},
MenuButtonAction::BackToSettings,
Expand Down
1 change: 0 additions & 1 deletion examples/mobile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ fn setup_scene(
bottom: Val::Px(50.0),
..default()
},
image: UiImage::default().with_color(Color::NONE),
..default()
},
BackgroundColor(Color::WHITE),
Expand Down
Loading