Skip to content

Commit c8763f6

Browse files
committed
Ui texture Atlas
1 parent 1b0969d commit c8763f6

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::{PositionedGlyph, Text, TextLayoutInfo};
3535
use bevy_transform::components::GlobalTransform;
@@ -165,20 +165,22 @@ pub fn extract_uinodes(
165165
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
166166
images: Extract<Res<Assets<Image>>>,
167167
ui_stack: Extract<Res<UiStack>>,
168+
atlas_layouts: Extract<Res<Assets<TextureAtlasLayout>>>,
168169
uinode_query: Extract<
169170
Query<(
170171
&Node,
171172
&GlobalTransform,
172173
&BackgroundColor,
173174
Option<&UiImage>,
174175
&ComputedVisibility,
176+
Option<&TextureAtlas>,
175177
Option<&CalculatedClip>,
176178
)>,
177179
>,
178180
) {
179181
extracted_uinodes.uinodes.clear();
180182
for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() {
181-
if let Ok((uinode, transform, color, maybe_image, visibility, clip)) =
183+
if let Ok((uinode, transform, color, maybe_image, visibility, atlas, clip)) =
182184
uinode_query.get(*entity)
183185
{
184186
// Skip invisible and completely transparent nodes
@@ -195,17 +197,33 @@ pub fn extract_uinodes(
195197
} else {
196198
(DEFAULT_IMAGE_HANDLE.typed().clone_weak(), false, false)
197199
};
198-
200+
// Skip loading images
201+
if !images.contains(&image) {
202+
continue;
203+
}
204+
// Skip completely transparent nodes
205+
if color.0.a() == 0.0 {
206+
continue;
207+
}
208+
let (atlas_size, rect_min) = atlas
209+
.and_then(|a| atlas_layouts.get(&a.layout).map(|l| (l, a.index)))
210+
.and_then(|(atlas, index)| {
211+
atlas
212+
.textures
213+
.get(index)
214+
.map(|rect| (Some(atlas.size), rect.min))
215+
})
216+
.unwrap_or((None, Vec2::ZERO));
199217
extracted_uinodes.uinodes.push(ExtractedUiNode {
200218
stack_index,
201219
transform: transform.compute_matrix(),
202220
color: color.0,
203221
rect: Rect {
204-
min: Vec2::ZERO,
205-
max: uinode.calculated_size,
222+
min: rect_min,
223+
max: rect_min + uinode.calculated_size,
206224
},
207225
image,
208-
atlas_size: None,
226+
atlas_size,
209227
clip: clip.map(|clip| clip.clip),
210228
flip_x,
211229
flip_y,

examples/ui/button.rs

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

@@ -43,7 +43,40 @@ fn button_system(
4343
}
4444
}
4545

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

0 commit comments

Comments
 (0)