├── .gitignore ├── bevy_mod_ui_texture_atlas_image.png ├── assets ├── numbered_grid_texture_atlas.png └── numbered_grid_texture_atlas_alpha.png ├── bevy_mod_ui_texture_atlas_image_long.png ├── LICENSE-APACHE ├── Cargo.toml ├── examples ├── minimal.rs ├── tiles.rs ├── alpha.rs └── clipped.rs ├── CHANGELOG.md ├── LICENSE ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /bevy_mod_ui_texture_atlas_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ickshonpe/bevy_mod_ui_texture_atlas_image/HEAD/bevy_mod_ui_texture_atlas_image.png -------------------------------------------------------------------------------- /assets/numbered_grid_texture_atlas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ickshonpe/bevy_mod_ui_texture_atlas_image/HEAD/assets/numbered_grid_texture_atlas.png -------------------------------------------------------------------------------- /bevy_mod_ui_texture_atlas_image_long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ickshonpe/bevy_mod_ui_texture_atlas_image/HEAD/bevy_mod_ui_texture_atlas_image_long.png -------------------------------------------------------------------------------- /assets/numbered_grid_texture_atlas_alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ickshonpe/bevy_mod_ui_texture_atlas_image/HEAD/assets/numbered_grid_texture_atlas_alpha.png -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Ickshonpe 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bevy_mod_ui_texture_atlas_image" 3 | version = "0.4.1" 4 | edition = "2021" 5 | license = "MIT OR Apache-2.0" 6 | keywords = ["bevy", "texture", "atlas", "ui", "games"] 7 | categories = ["game-development", "graphics", "gui"] 8 | repository = "https://github.com/ickshonpe/bevy_mod_ui_texture_atlas_image" 9 | readme = "README.md" 10 | description = "Draw images from texture atlases with the Bevy UI" 11 | 12 | [dependencies.bevy] 13 | version = "0.10" 14 | default_features= false 15 | features = ["bevy_asset", "bevy_render", "bevy_ui", "bevy_sprite"] 16 | 17 | [dev-dependencies] 18 | bevy = "0.10" -------------------------------------------------------------------------------- /examples/minimal.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_mod_ui_texture_atlas_image::*; 3 | 4 | fn setup( 5 | mut commands: Commands, 6 | asset_server: Res, 7 | mut texture_atlases: ResMut>, 8 | ) { 9 | commands.spawn(Camera2dBundle::default()); 10 | let texture_atlas = TextureAtlas::from_grid( 11 | asset_server.load("numbered_grid_texture_atlas.png"), 12 | 16. * Vec2::ONE, 13 | 4, 14 | 4, 15 | None, 16 | None, 17 | ); 18 | let atlas = texture_atlases.add(texture_atlas); 19 | commands.spawn(AtlasImageBundle { 20 | atlas_image: UiAtlasImage::new(atlas, 0), 21 | ..Default::default() 22 | }); 23 | } 24 | 25 | fn main() { 26 | App::new() 27 | .add_plugins(DefaultPlugins) 28 | .add_plugin(UiAtlasImagePlugin) 29 | .add_startup_system(setup) 30 | .run(); 31 | } 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Version 0.4.1 2 | * Fixed incorrect scaling of clipped texture atlas images. 3 | * Added a new example `clipped`. 4 | 5 | # Version 0.4.0 6 | * Added `ImageTint` component (by Nionidh). 7 | * Removed `BackgroundColor` from `AtlasImageBundle` and replaced it with `ImageTint` (by Nionidh). 8 | * Query for `ImageTint` instead of `BackgroundColor` in the `extract_texture_atlas_image_uinodes` system (by Nionidh). 9 | * Added a new example `alpha` (by Nionidh). 10 | * Added `CHANGELOG.md`, this changelog. 11 | 12 | # Version 0.3.0 13 | * Bevy 0.10 support 14 | * Added image flipping on the x and y-axes 15 | * Added a `new` method on `UiAtlasImage` to create a `UiAtlasImage` from a `TextureAtlas` handle an index. 16 | 17 | # Version 0.2.4 18 | * Skip nodes during extraction if either of its dimensions has zero length. 19 | * Moved the alpha check to before retrieving the atlas 20 | 21 | # Version 0.2.2 22 | * Added a `ZIndex` component to the `AtlasImageBundle` 23 | 24 | # Version 0.2.0 25 | * Bevy 0.9 support 26 | 27 | # Version 0.1.0 28 | * Bevy 0.8 support 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ickshonpe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /examples/tiles.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_mod_ui_texture_atlas_image::AtlasImageBundle; 3 | use bevy_mod_ui_texture_atlas_image::UiAtlasImage; 4 | use bevy_mod_ui_texture_atlas_image::UiAtlasImagePlugin; 5 | 6 | fn setup( 7 | mut commands: Commands, 8 | asset_server: Res, 9 | mut texture_atlases: ResMut>, 10 | ) { 11 | commands.spawn(Camera2dBundle::default()); 12 | 13 | // The source image for the atlas has tiles labelled with numbers that correspond 14 | // to their respective indices assigned by TextureAtlas::from_grid. 15 | let image = asset_server.load("numbered_grid_texture_atlas.png"); 16 | let texture_atlas = TextureAtlas::from_grid(image.clone(), 16. * Vec2::ONE, 4, 4, None, None); 17 | let texture_atlas_handle = texture_atlases.add(texture_atlas); 18 | 19 | // Root ui node that fills the window. 20 | commands 21 | .spawn(NodeBundle { 22 | style: Style { 23 | size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), 24 | justify_content: JustifyContent::Center, 25 | ..Default::default() 26 | }, 27 | background_color: BackgroundColor(Color::NONE), 28 | ..Default::default() 29 | }) 30 | .with_children(|builder| { 31 | // Spawn UiAtlasImage ui nodes for the tiles numbered 0, 5, and 14. 32 | for index in [0, 5, 14] { 33 | builder.spawn(AtlasImageBundle { 34 | atlas_image: UiAtlasImage::new(texture_atlas_handle.clone(), index), 35 | ..Default::default() 36 | }); 37 | } 38 | // Spawn an ordinary Image ui node displaying the source atlas image. 39 | builder.spawn(ImageBundle { 40 | image: image.into(), 41 | ..Default::default() 42 | }); 43 | }); 44 | } 45 | 46 | fn main() { 47 | App::new() 48 | .add_plugins( 49 | DefaultPlugins 50 | // Change the default image filtering to nearest so the images are sharp. 51 | .set(ImagePlugin::default_nearest()), 52 | ) 53 | .add_plugin(UiAtlasImagePlugin) 54 | .add_startup_system(setup) 55 | .run(); 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bevy_mod_ui_texture_atlas_image 2 | [![crates.io](https://img.shields.io/crates/v/bevy_mod_ui_texture_atlas_image)](https://crates.io/crates/bevy_mod_ui_texture_atlas_image) 3 | [![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/ickshonpe/bevy_mod_ui_texture_atlas_image) 4 | [![crates.io](https://img.shields.io/crates/d/bevy_mod_ui_texture_atlas_image)](https://crates.io/crates/bevy_mod_ui_texture_atlas_image) 5 | 6 | Draw images from texture atlases with the Bevy UI. 7 | 8 | ![image](bevy_mod_ui_texture_atlas_image_long.png) 9 | 10 | * Versions 0.3 and 0.4 support Bevy 0.10 11 | * Version 0.2 supports Bevy 0.9 12 | * Version 0.1 supports Bevy 0.8 13 | # 14 | 15 | ## Details 16 | 17 | To use this crate, add its dependency to your project's `Cargo.toml`: 18 | 19 | ```toml 20 | bevy_mod_ui_texture_atlas_image = "0.3" 21 | ``` 22 | 23 | or with Cargo: 24 | 25 | ``` 26 | cargo add bevy_mod_ui_texture_atlas_image 27 | ``` 28 | 29 | ## Components 30 | * `UiAtlasImage` 31 | 32 | The texture atlas image of the node. 33 | * `ImageTint` 34 | 35 | The tint color of the image. 36 | 37 | ## Bundles 38 | * `AtlasImageBundle` 39 | 40 | The bundle of components needed to display an image from a `TextureAtlas` with the Bevy UI. 41 | 42 | ## Plugin 43 | The ```UiAtlasImagePlugin``` plugin must be added to your Bevy App: 44 | 45 | ```rust 46 | use bevy_mod_ui_texture_atlas_image::*; 47 | 48 | fn main () { 49 | App::new() 50 | .add_plugins(DefaultPlugins) 51 | .add_plugin(UiAtlasImagePlugin) 52 | // ..rest of app 53 | .run() 54 | } 55 | ``` 56 | 57 | Then you can spawn an `AtlasImageBundle` to draw images from a `TextureAtlas` with the Bevy UI: 58 | ```rust 59 | commands 60 | .spawn(AtlasImageBundle { 61 | atlas_image: UiAtlasImage { 62 | atlas: texture_atlas_handle.clone(), 63 | index: 5 64 | }, 65 | ..Default::default() 66 | }); 67 | ``` 68 | The differences between an `AtlasImageBundle` and an `ImageBundle` are that 69 | * Instead of a `UiImage` component, `AtlasImageBundle` has a `UiAtlasImage` component that sets the image displayed by the node. 70 | * Instead of a `BackgroundColor` component, `AtlasImageBundle` has an `ImageTint` component that sets the color tint of the image. 71 | 72 | # 73 | ### Examples 74 | 75 | * Displaying a single image from a texture atlas: 76 | ``` 77 | cargo --run --example minimal 78 | ``` 79 | * Displaying three tiles from a texture atlas grid alongside the atlas's source image: 80 | ``` 81 | cargo --run --example tiles 82 | ``` 83 | * Displaying images from a texture atlas with an alpha channel. 84 | ``` 85 | cargo --run --example alpha 86 | ``` 87 | * Displaying images from a texture atlas with clipping. 88 | ``` 89 | cargo --run --example clipped 90 | ``` -------------------------------------------------------------------------------- /examples/alpha.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_mod_ui_texture_atlas_image::AtlasImageBundle; 3 | use bevy_mod_ui_texture_atlas_image::UiAtlasImage; 4 | use bevy_mod_ui_texture_atlas_image::UiAtlasImagePlugin; 5 | 6 | fn setup( 7 | mut commands: Commands, 8 | asset_server: Res, 9 | mut texture_atlases: ResMut>, 10 | ) { 11 | commands.spawn(Camera2dBundle::default()); 12 | 13 | // The source image for the atlas has tiles labelled with numbers that correspond 14 | // to their respective indices assigned by TextureAtlas::from_grid. 15 | let image = asset_server.load("numbered_grid_texture_atlas_alpha.png"); 16 | let texture_atlas = TextureAtlas::from_grid(image.clone(), 16. * Vec2::ONE, 4, 2, None, None); 17 | let texture_atlas_handle = texture_atlases.add(texture_atlas); 18 | 19 | // Root ui node that fills the window. 20 | commands 21 | .spawn(NodeBundle { 22 | style: Style { 23 | size: Size::new(Val::Percent(100.0), Val::Percent(100.0)), 24 | justify_content: JustifyContent::Center, 25 | ..Default::default() 26 | }, 27 | background_color: BackgroundColor(Color::NONE), 28 | ..Default::default() 29 | }) 30 | .with_children(|builder| { 31 | // Spawn UiAtlasImage ui nodes for the tiles numbered 0, 5, and 14. 32 | for index in [0, 2, 4, 6, 7] { 33 | builder.spawn(AtlasImageBundle { 34 | atlas_image: UiAtlasImage::new(texture_atlas_handle.clone(), index), 35 | style: Style { 36 | position: UiRect { 37 | left: Val::Px((index * 15) as f32), 38 | top: Val::Px((index * 15) as f32), 39 | right: Val::Auto, 40 | bottom: Val::Auto, 41 | }, 42 | size: Size { 43 | width: Val::Px(64.0), 44 | height: Val::Px(64.0), 45 | }, 46 | position_type: PositionType::Absolute, 47 | ..Default::default() 48 | }, 49 | ..Default::default() 50 | }); 51 | } 52 | // Spawn an ordinary Image ui node displaying the source atlas image. 53 | builder.spawn(ImageBundle { 54 | image: image.into(), 55 | style: Style { 56 | margin: UiRect { 57 | left: Val::Auto, 58 | right: Val::Px(0.), 59 | top: Val::Auto, 60 | bottom: Val::Px(0.), 61 | }, 62 | ..Default::default() 63 | }, 64 | background_color: Color::rgba(0., 1., 0., 1.).into(), 65 | ..Default::default() 66 | }); 67 | }); 68 | } 69 | 70 | fn main() { 71 | App::new() 72 | .add_plugins( 73 | DefaultPlugins 74 | // Change the default image filtering to nearest so the images are sharp. 75 | .set(ImagePlugin::default_nearest()), 76 | ) 77 | .add_plugin(UiAtlasImagePlugin) 78 | .add_startup_system(setup) 79 | .run(); 80 | } 81 | -------------------------------------------------------------------------------- /examples/clipped.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy_mod_ui_texture_atlas_image::*; 3 | 4 | fn setup( 5 | mut commands: Commands, 6 | asset_server: Res, 7 | mut texture_atlases: ResMut>, 8 | ) { 9 | commands.spawn(Camera2dBundle::default()); 10 | let texture_atlas = TextureAtlas::from_grid( 11 | asset_server.load("numbered_grid_texture_atlas.png"), 12 | 16. * Vec2::ONE, 13 | 4, 14 | 4, 15 | None, 16 | None, 17 | ); 18 | let atlas = texture_atlases.add(texture_atlas); 19 | commands 20 | .spawn(NodeBundle { 21 | style: Style { 22 | flex_basis: Val::Percent(100.), 23 | align_items: AlignItems::Center, 24 | justify_content: JustifyContent::Center, 25 | gap: Size::all(Val::Px(100.)), 26 | ..Default::default() 27 | }, 28 | ..Default::default() 29 | }) 30 | .with_children(|parent| { 31 | parent 32 | .spawn(NodeBundle { 33 | style: Style { 34 | size: Size::all(Val::Px(400.)), 35 | overflow: Overflow::Hidden, 36 | ..Default::default() 37 | }, 38 | background_color: Color::RED.into(), 39 | ..Default::default() 40 | }) 41 | .with_children(|parent| { 42 | parent.spawn(AtlasImageBundle { 43 | style: Style { 44 | size: Size::all(Val::Px(400.)), 45 | position: UiRect { 46 | bottom: Val::Px(100.), 47 | right: Val::Px(100.), 48 | ..default() 49 | }, 50 | ..Default::default() 51 | }, 52 | color: TintColor(Color::WHITE), 53 | atlas_image: UiAtlasImage::new(atlas.clone(), 5), 54 | ..Default::default() 55 | }); 56 | }); 57 | 58 | parent 59 | .spawn(NodeBundle { 60 | style: Style { 61 | size: Size::all(Val::Px(400.)), 62 | overflow: Overflow::Hidden, 63 | ..Default::default() 64 | }, 65 | background_color: Color::GREEN.into(), 66 | ..Default::default() 67 | }) 68 | .with_children(|parent| { 69 | parent.spawn(AtlasImageBundle { 70 | style: Style { 71 | size: Size::all(Val::Px(400.)), 72 | position: UiRect { 73 | top: Val::Px(100.), 74 | left: Val::Px(100.), 75 | ..default() 76 | }, 77 | ..Default::default() 78 | }, 79 | color: TintColor(Color::WHITE), 80 | atlas_image: UiAtlasImage::new(atlas, 8), 81 | ..Default::default() 82 | }); 83 | }); 84 | }); 85 | } 86 | 87 | fn main() { 88 | App::new() 89 | .add_plugins(DefaultPlugins) 90 | .add_plugin(UiAtlasImagePlugin) 91 | .add_startup_system(setup) 92 | .run(); 93 | } 94 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use bevy::prelude::*; 2 | use bevy::render::Extract; 3 | use bevy::render::RenderApp; 4 | use bevy::ui::ExtractedUiNode; 5 | use bevy::ui::ExtractedUiNodes; 6 | use bevy::ui::FocusPolicy; 7 | use bevy::ui::RenderUiSystem; 8 | use bevy::ui::UiStack; 9 | use bevy::ui::UiSystem; 10 | 11 | /// A component that represents an image from a `TextureAtlas`. 12 | #[derive(Component, Clone, Debug, Default, Reflect)] 13 | #[reflect(Component, Default)] 14 | pub struct UiAtlasImage { 15 | /// assets handle of the texture atlas 16 | pub atlas: Handle, 17 | /// index of the image in the texture atlas 18 | pub index: usize, 19 | /// Whether the image should be flipped along its x-axis 20 | pub flip_x: bool, 21 | /// Whether the image should be flipped along its y-axis 22 | pub flip_y: bool, 23 | } 24 | 25 | impl UiAtlasImage { 26 | /// Creates a new `UiAtlasImage` from a `TextureAtlas` handle and an index. 27 | pub fn new(atlas: Handle, index: usize) -> Self { 28 | Self { 29 | atlas, 30 | index, 31 | flip_x: false, 32 | flip_y: false, 33 | } 34 | } 35 | } 36 | 37 | /// The tint color of the image 38 | /// 39 | /// When combined with [`UiAtlasImage`], tints the provided texture, while still 40 | /// respecting transparent areas. 41 | #[derive(Component, Copy, Clone, Debug, Reflect)] 42 | #[reflect(Component, Default)] 43 | pub struct TintColor(pub Color); 44 | 45 | impl TintColor { 46 | pub const DEFAULT: Self = Self(Color::WHITE); 47 | } 48 | 49 | impl Default for TintColor { 50 | fn default() -> Self { 51 | Self::DEFAULT 52 | } 53 | } 54 | 55 | impl From for TintColor { 56 | fn from(color: Color) -> Self { 57 | Self(color) 58 | } 59 | } 60 | 61 | /// A UI node that is an image from a texture atlas 62 | #[derive(Bundle, Clone, Debug, Default)] 63 | pub struct AtlasImageBundle { 64 | /// Describes the size of the node 65 | pub node: Node, 66 | /// Describes the style including flexbox settings 67 | pub style: Style, 68 | /// The calculated size based on the given image 69 | pub calculated_size: CalculatedSize, 70 | /// The tint color of the image 71 | pub color: TintColor, 72 | /// The texture atlas image of the node 73 | pub atlas_image: UiAtlasImage, 74 | /// Whether this node should block interaction with lower nodes 75 | pub focus_policy: FocusPolicy, 76 | /// The transform of the node 77 | pub transform: Transform, 78 | /// The global transform of the node 79 | pub global_transform: GlobalTransform, 80 | /// Describes the visibility properties of the node 81 | pub visibility: Visibility, 82 | /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering 83 | pub computed_visibility: ComputedVisibility, 84 | /// Indicates the depth at which the node should appear in the UI 85 | pub z_index: ZIndex, 86 | } 87 | 88 | fn texture_atlas_image_node_system( 89 | texture_atlases: Res>, 90 | mut query: Query<(&mut CalculatedSize, &UiAtlasImage)>, 91 | ) { 92 | for (mut calculated_size, atlas_image) in &mut query { 93 | if let Some(atlas) = texture_atlases.get(&atlas_image.atlas) { 94 | let size = atlas.textures[atlas_image.index].size(); 95 | if size != calculated_size.size { 96 | calculated_size.size = size; 97 | calculated_size.preserve_aspect_ratio = true; 98 | } 99 | } 100 | } 101 | } 102 | 103 | #[allow(clippy::type_complexity)] 104 | fn extract_texture_atlas_image_uinodes( 105 | mut extracted_uinodes: ResMut, 106 | images: Extract>>, 107 | texture_atlases: Extract>>, 108 | ui_stack: Extract>, 109 | uinode_query: Extract< 110 | Query<( 111 | &Node, 112 | &GlobalTransform, 113 | &TintColor, 114 | &UiAtlasImage, 115 | &ComputedVisibility, 116 | Option<&CalculatedClip>, 117 | )>, 118 | >, 119 | ) { 120 | for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { 121 | if let Ok((uinode, global_transform, color, atlas_image, visibility, clip)) = 122 | uinode_query.get(*entity) 123 | { 124 | if !visibility.is_visible() 125 | || uinode.size().x == 0. 126 | || uinode.size().y == 0. 127 | || color.0.a() == 0.0 128 | { 129 | continue; 130 | } 131 | 132 | if let Some(texture_atlas) = texture_atlases.get(&atlas_image.atlas) { 133 | let image = texture_atlas.texture.clone_weak(); 134 | if !images.contains(&image) { 135 | continue; 136 | } 137 | let mut rect = texture_atlas.textures[atlas_image.index]; 138 | let scale = uinode.size() / rect.size(); 139 | rect.min *= scale; 140 | rect.max *= scale; 141 | extracted_uinodes.uinodes.push(ExtractedUiNode { 142 | stack_index, 143 | transform: global_transform.compute_matrix(), 144 | color: color.0, 145 | rect, 146 | image, 147 | atlas_size: Some(texture_atlas.size * scale), 148 | clip: clip.map(|clip| clip.clip), 149 | flip_x: atlas_image.flip_x, 150 | flip_y: atlas_image.flip_y, 151 | }); 152 | } 153 | } 154 | } 155 | } 156 | pub struct UiAtlasImagePlugin; 157 | 158 | impl Plugin for UiAtlasImagePlugin { 159 | fn build(&self, app: &mut App) { 160 | app.register_type::().add_system( 161 | texture_atlas_image_node_system 162 | .before(UiSystem::Flex) 163 | .in_base_set(CoreSet::PostUpdate), 164 | ); 165 | 166 | let render_app = match app.get_sub_app_mut(RenderApp) { 167 | Ok(render_app) => render_app, 168 | Err(_) => return, 169 | }; 170 | 171 | render_app.add_system( 172 | extract_texture_atlas_image_uinodes 173 | .after(RenderUiSystem::ExtractNode) 174 | .in_schedule(ExtractSchedule), 175 | ); 176 | } 177 | } 178 | --------------------------------------------------------------------------------