Skip to content

Commit 75d8fd0

Browse files
committed
Ui texture Atlas
1 parent 19e4f3f commit 75d8fd0

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

crates/bevy_ui/src/render/mod.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use bevy_render::{
2929
};
3030
use bevy_sprite::SpriteAssetEvents;
3131
#[cfg(feature = "bevy_text")]
32-
use bevy_sprite::TextureAtlasLayout;
32+
use bevy_sprite::{TextureAtlas, TextureAtlasLayout};
3333
#[cfg(feature = "bevy_text")]
3434
use bevy_text::{Text, TextLayoutInfo};
3535
use bevy_transform::components::GlobalTransform;
@@ -188,20 +188,22 @@ pub fn extract_uinodes(
188188
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
189189
images: Extract<Res<Assets<Image>>>,
190190
ui_stack: Extract<Res<UiStack>>,
191+
atlas_layouts: Extract<Res<Assets<TextureAtlasLayout>>>,
191192
uinode_query: Extract<
192193
Query<(
193194
&Node,
194195
&GlobalTransform,
195196
&BackgroundColor,
196197
Option<&UiImage>,
197198
&ComputedVisibility,
199+
Option<&TextureAtlas>,
198200
Option<&CalculatedClip>,
199201
)>,
200202
>,
201203
) {
202204
extracted_uinodes.uinodes.clear();
203205
for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() {
204-
if let Ok((uinode, transform, color, maybe_image, visibility, clip)) =
206+
if let Ok((uinode, transform, color, maybe_image, visibility, atlas, clip)) =
205207
uinode_query.get(*entity)
206208
{
207209
// Skip invisible and completely transparent nodes
@@ -218,17 +220,33 @@ pub fn extract_uinodes(
218220
} else {
219221
(DEFAULT_IMAGE_HANDLE.typed().clone_weak(), false, false)
220222
};
221-
223+
// Skip loading images
224+
if !images.contains(&image) {
225+
continue;
226+
}
227+
// Skip completely transparent nodes
228+
if color.0.a() == 0.0 {
229+
continue;
230+
}
231+
let (atlas_size, rect_min) = atlas
232+
.and_then(|a| atlas_layouts.get(&a.layout).map(|l| (l, a.index)))
233+
.and_then(|(atlas, index)| {
234+
atlas
235+
.textures
236+
.get(index)
237+
.map(|rect| (Some(atlas.size), rect.min))
238+
})
239+
.unwrap_or((None, Vec2::ZERO));
222240
extracted_uinodes.uinodes.push(ExtractedUiNode {
223241
stack_index,
224242
transform: transform.compute_matrix(),
225243
color: color.0,
226244
rect: Rect {
227-
min: Vec2::ZERO,
228-
max: uinode.calculated_size,
245+
min: rect_min,
246+
max: rect_min + uinode.calculated_size,
229247
},
230248
image,
231-
atlas_size: None,
249+
atlas_size,
232250
clip: clip.map(|clip| clip.clip),
233251
flip_x,
234252
flip_y,

examples/ui/button.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn main() {
88
.add_plugins(DefaultPlugins)
99
// Only run the app when there is user input. This will significantly reduce CPU/GPU use.
1010
.insert_resource(WinitSettings::desktop_app())
11-
.add_systems((setup.on_startup(), button_system))
11+
.add_systems((setup.on_startup(), button_system, sheet_button_system))
1212
.run();
1313
}
1414

@@ -42,7 +42,40 @@ fn button_system(
4242
}
4343
}
4444

45-
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
45+
fn sheet_button_system(
46+
mut interaction_query: Query<
47+
(&Interaction, &mut TextureAtlas),
48+
(Changed<Interaction>, With<Button>),
49+
>,
50+
) {
51+
for (interaction, mut atlas) in interaction_query.iter_mut() {
52+
match *interaction {
53+
Interaction::Clicked => {
54+
atlas.index = 2;
55+
}
56+
Interaction::Hovered => {
57+
atlas.index = 1;
58+
}
59+
Interaction::None => {
60+
atlas.index = 0;
61+
}
62+
}
63+
}
64+
}
65+
66+
fn setup(
67+
mut commands: Commands,
68+
asset_server: Res<AssetServer>,
69+
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
70+
) {
71+
let handle = asset_server.load("textures/array_texture.png");
72+
let layout = texture_atlas_layouts.add(TextureAtlasLayout::from_grid(
73+
Vec2::splat(250.0),
74+
1,
75+
4,
76+
None,
77+
None,
78+
));
4679
// ui camera
4780
commands.spawn(Camera2dBundle::default());
4881
commands
@@ -56,6 +89,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
5689
..default()
5790
})
5891
.with_children(|parent| {
92+
// Classic button
5993
parent
6094
.spawn(ButtonBundle {
6195
style: Style {
@@ -64,6 +98,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
6498
justify_content: JustifyContent::Center,
6599
// vertically center child text
66100
align_items: AlignItems::Center,
101+
// center button
102+
margin: UiRect::all(Val::Auto),
67103
..default()
68104
},
69105
background_color: NORMAL_BUTTON.into(),
@@ -79,5 +115,18 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
79115
},
80116
));
81117
});
118+
// Texture sheet button
119+
parent
120+
.spawn(ButtonBundle {
121+
style: Style {
122+
size: Size::new(Val::Px(150.0), Val::Px(65.0)),
123+
// center button
124+
margin: UiRect::all(Val::Auto),
125+
..default()
126+
},
127+
image: handle.into(),
128+
..default()
129+
})
130+
.insert(TextureAtlas { layout, index: 0 });
82131
});
83132
}

0 commit comments

Comments
 (0)