Skip to content

Commit 531d1b4

Browse files
committed
Ui texture Atlas
1 parent 8ec1e90 commit 531d1b4

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;
@@ -166,20 +166,22 @@ pub fn extract_uinodes(
166166
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
167167
images: Extract<Res<Assets<Image>>>,
168168
ui_stack: Extract<Res<UiStack>>,
169+
atlas_layouts: Extract<Res<Assets<TextureAtlasLayout>>>,
169170
uinode_query: Extract<
170171
Query<(
171172
&Node,
172173
&GlobalTransform,
173174
&BackgroundColor,
174175
Option<&UiImage>,
175176
&ComputedVisibility,
177+
Option<&TextureAtlas>,
176178
Option<&CalculatedClip>,
177179
)>,
178180
>,
179181
) {
180182
extracted_uinodes.uinodes.clear();
181183
for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() {
182-
if let Ok((uinode, transform, color, maybe_image, visibility, clip)) =
184+
if let Ok((uinode, transform, color, maybe_image, visibility, atlas, clip)) =
183185
uinode_query.get(*entity)
184186
{
185187
// Skip invisible and completely transparent nodes
@@ -196,17 +198,33 @@ pub fn extract_uinodes(
196198
} else {
197199
(DEFAULT_IMAGE_HANDLE.typed().clone_weak(), false, false)
198200
};
199-
201+
// Skip loading images
202+
if !images.contains(&image) {
203+
continue;
204+
}
205+
// Skip completely transparent nodes
206+
if color.0.a() == 0.0 {
207+
continue;
208+
}
209+
let (atlas_size, rect_min) = atlas
210+
.and_then(|a| atlas_layouts.get(&a.layout).map(|l| (l, a.index)))
211+
.and_then(|(atlas, index)| {
212+
atlas
213+
.textures
214+
.get(index)
215+
.map(|rect| (Some(atlas.size), rect.min))
216+
})
217+
.unwrap_or((None, Vec2::ZERO));
200218
extracted_uinodes.uinodes.push(ExtractedUiNode {
201219
stack_index,
202220
transform: transform.compute_matrix(),
203221
color: color.0,
204222
rect: Rect {
205-
min: Vec2::ZERO,
206-
max: uinode.calculated_size,
223+
min: rect_min,
224+
max: rect_min + uinode.calculated_size,
207225
},
208226
image,
209-
atlas_size: None,
227+
atlas_size,
210228
clip: clip.map(|clip| clip.clip),
211229
flip_x,
212230
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)