Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
970 additions
and
596 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
use bevy::prelude::*; | ||
use bevy::utils::HashSet; | ||
use bevy_sprite::ImageScaleMode; | ||
|
||
use crate::plugin::TextModeExtractedSprite; | ||
use crate::TextModeSprite; | ||
|
||
/// Component storing texture slices for sprite entities with a [`ImageScaleMode`] | ||
/// | ||
/// This component is automatically inserted and updated | ||
#[derive(Debug, Clone, Component)] | ||
pub struct ComputedTextModeTextureSlices(Vec<TextureSlice>); | ||
|
||
impl ComputedTextModeTextureSlices { | ||
/// Computes [`TextModeExtractedSprite`] iterator from the sprite slices | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `transform` - the sprite entity global transform | ||
/// * `original_entity` - the sprite entity | ||
/// * `sprite` - The sprite component | ||
/// * `handle` - The sprite texture handle | ||
#[must_use] | ||
pub(crate) fn extract_text_mode_sprites<'a>( | ||
&'a self, | ||
transform: &'a GlobalTransform, | ||
original_entity: Entity, | ||
sprite: &'a TextModeSprite, | ||
handle: &'a Handle<Image>, | ||
) -> impl ExactSizeIterator<Item = TextModeExtractedSprite> + 'a { | ||
let mut flip = Vec2::ONE; | ||
let [mut flip_x, mut flip_y] = [false; 2]; | ||
if sprite.flip_x { | ||
flip.x *= -1.0; | ||
flip_x = true; | ||
} | ||
if sprite.flip_y { | ||
flip.y *= -1.0; | ||
flip_y = true; | ||
} | ||
self.0.iter().map(move |slice| { | ||
let offset = (slice.offset * flip).extend(0.0); | ||
let transform = transform.mul_transform(Transform::from_translation(offset)); | ||
TextModeExtractedSprite { | ||
transform, | ||
bg: sprite.bg, | ||
fg: sprite.fg, | ||
alpha: sprite.alpha, | ||
custom_size: Some(slice.draw_size), | ||
image_handle_id: handle.id(), | ||
flip_x, | ||
flip_y, | ||
rotation: sprite.rotation, | ||
anchor: sprite.anchor.as_vec(), | ||
rect: sprite.rect, | ||
original_entity: Some(original_entity), | ||
} | ||
}) | ||
} | ||
} | ||
|
||
/// Generates sprite slices for a `sprite` given a `scale_mode`. The slices | ||
/// will be computed according to the `image_handle` dimensions or the sprite rect. | ||
/// | ||
/// Returns `None` if the image asset is not loaded | ||
#[must_use] | ||
fn compute_text_mode_sprite_slices( | ||
sprite: &TextModeSprite, | ||
scale_mode: &ImageScaleMode, | ||
image_handle: &Handle<Image>, | ||
images: &Assets<Image>, | ||
) -> Option<ComputedTextModeTextureSlices> { | ||
let image_size = images.get(image_handle).map(|i| { | ||
Vec2::new( | ||
i.texture_descriptor.size.width as f32, | ||
i.texture_descriptor.size.height as f32, | ||
) | ||
})?; | ||
let slices = match scale_mode { | ||
ImageScaleMode::Sliced(slicer) => slicer.compute_slices( | ||
Rect { | ||
min: Vec2::ZERO, | ||
max: image_size, | ||
}, | ||
sprite.custom_size, | ||
), | ||
ImageScaleMode::Tiled { | ||
tile_x, | ||
tile_y, | ||
stretch_value, | ||
} => { | ||
let slice = TextureSlice { | ||
texture_rect: Rect { | ||
min: Vec2::ZERO, | ||
max: image_size, | ||
}, | ||
draw_size: sprite.custom_size.unwrap_or(image_size), | ||
offset: Vec2::ZERO, | ||
}; | ||
slice.tiled(*stretch_value, (*tile_x, *tile_y)) | ||
} | ||
}; | ||
Some(ComputedTextModeTextureSlices(slices)) | ||
} | ||
|
||
/// System reacting to added or modified [`Image`] handles, and recompute sprite slices | ||
/// on matching sprite entities with a [`ImageScaleMode`] component | ||
pub(crate) fn compute_text_mode_slices_on_asset_event( | ||
mut commands: Commands, | ||
mut events: EventReader<AssetEvent<Image>>, | ||
images: Res<Assets<Image>>, | ||
sprites: Query<(Entity, &ImageScaleMode, &TextModeSprite, &Handle<Image>)>, | ||
) { | ||
// We store the asset ids of added/modified image assets | ||
let added_handles: HashSet<_> = events | ||
.read() | ||
.filter_map(|e| match e { | ||
AssetEvent::Added { id } | AssetEvent::Modified { id } => Some(*id), | ||
_ => None, | ||
}) | ||
.collect(); | ||
if added_handles.is_empty() { | ||
return; | ||
} | ||
// We recompute the sprite slices for sprite entities with a matching asset handle id | ||
for (entity, scale_mode, sprite, image_handle) in &sprites { | ||
if !added_handles.contains(&image_handle.id()) { | ||
continue; | ||
} | ||
if let Some(slices) = compute_text_mode_sprite_slices(sprite, scale_mode, image_handle, &images) { | ||
commands.entity(entity).insert(slices); | ||
} | ||
} | ||
} | ||
|
||
/// System reacting to changes on relevant sprite bundle components to compute the sprite slices | ||
/// on matching sprite entities with a [`ImageScaleMode`] component | ||
pub(crate) fn compute_text_mode_slices_on_sprite_change( | ||
mut commands: Commands, | ||
images: Res<Assets<Image>>, | ||
changed_sprites: Query< | ||
(Entity, &ImageScaleMode, &TextModeSprite, &Handle<Image>), | ||
Or<( | ||
Changed<ImageScaleMode>, | ||
Changed<Handle<Image>>, | ||
Changed<TextModeSprite>, | ||
)>, | ||
>, | ||
) { | ||
for (entity, scale_mode, sprite, image_handle) in &changed_sprites { | ||
if let Some(slices) = compute_text_mode_sprite_slices(sprite, scale_mode, image_handle, &images) { | ||
commands.entity(entity).insert(slices); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
pub use plugin::TextModePlugin; | ||
pub use text_mode_texture_atlas::TextModeSprite; | ||
pub use text_mode_texture_atlas::TextModeSpriteBundle; | ||
|
||
mod plugin; | ||
mod text_mode_texture_atlas; | ||
mod computed_text_mode_slices; | ||
|
||
pub use plugin::TextModePlugin; | ||
pub use text_mode_texture_atlas::TextModeTextureAtlasSprite; | ||
pub use text_mode_texture_atlas::TextModeSpriteSheetBundle; |
Oops, something went wrong.