Skip to content

Commit

Permalink
lib: Update to Bevy 0.13
Browse files Browse the repository at this point in the history
  • Loading branch information
yopox committed Mar 12, 2024
1 parent b1a7612 commit 2fa04da
Show file tree
Hide file tree
Showing 10 changed files with 970 additions and 596 deletions.
995 changes: 574 additions & 421 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Cargo.toml
@@ -1,5 +1,5 @@
[dependencies.bevy]
version = "0.12.1"
version = "0.13"

[dependencies.bitflags]
version = "2.3"
Expand All @@ -11,6 +11,9 @@ features = ["derive"]
[dependencies.fixedbitset]
version = "0.4"

[dependencies.bevy_sprite]
version = "0.13"

[package]
authors = ["yopox yopoxdev@gmail.com"]
description = "Bevy plugin adding a texture atlas sprite with configurable background and foreground colors."
Expand Down
Binary file modified assets/texmod.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 44 additions & 13 deletions examples/sprite_atlas.rs
@@ -1,9 +1,10 @@
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy_text_mode::{TextModePlugin, TextModeSpriteSheetBundle, TextModeTextureAtlasSprite};

use bevy_text_mode::{TextModePlugin, TextModeSprite, TextModeSpriteBundle};

const WIDTH: f32 = 8. * 8. * 8.;
const HEIGHT: f32 = 4. * 8. * 8.;
const HEIGHT: f32 = 7. * 8. * 8.;

fn main() {
App::new()
Expand Down Expand Up @@ -67,15 +68,11 @@ impl Into<Color> for Light {
fn init(
mut commands: Commands,
server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
let tileset: Handle<Image> = server.load("texmod.png");
let texture_atlas = TextureAtlas::from_grid(
tileset.clone(),
Vec2::new(8.0, 8.0), 6, 1,
None, None
);
let handle = texture_atlases.add(texture_atlas);
let layout = TextureAtlasLayout::from_grid(Vec2::new(8., 8.), 7, 1, None, None);
let handle = texture_atlas_layouts.add(layout);

commands.spawn(Camera2dBundle {
transform: Transform {
Expand All @@ -97,15 +94,49 @@ fn init(
(5, 2, 5, Light::ORANGE.into(), Dark::ORANGE.into()),
(6, 2, 1, Light::WHITE.into(), Dark::PINK.into()),
] {
commands.spawn(TextModeSpriteSheetBundle {
sprite: TextModeTextureAtlasSprite {
index: i,
commands.spawn(TextModeSpriteBundle {
sprite: TextModeSprite {
bg,
fg,
anchor: Anchor::TopLeft,
..default()
},
texture_atlas: handle.clone(),
atlas: TextureAtlas {
layout: handle.clone(),
index: i,
},
texture: tileset.clone(),
transform: Transform::from_xyz(8. * x as f32, -8. * y as f32, 0.),
..default()
});
}

for (x, y, i, flip_x, flip_y, rotation) in [
(1, 4, 6, false, false, 0),
(2, 4, 6, false, false, 1),
(3, 4, 6, false, false, 2),
(4, 4, 6, false, false, 3),

(3, 5, 6, false, false, 0),
(4, 5, 6, true, false, 0),
(5, 5, 6, false, true, 0),
(6, 5, 6, true, true, 0),
] {
commands.spawn(TextModeSpriteBundle {
sprite: TextModeSprite {
bg: Light::WHITE.into(),
fg: Dark::BLACK.into(),
flip_x,
flip_y,
rotation,
anchor: Anchor::TopLeft,
..default()
},
atlas: TextureAtlas {
layout: handle.clone(),
index: i,
},
texture: tileset.clone(),
transform: Transform::from_xyz(8. * x as f32, -8. * y as f32, 0.),
..default()
});
Expand Down
10 changes: 5 additions & 5 deletions readme.md
Expand Up @@ -6,31 +6,31 @@
<img src="https://raw.githubusercontent.com/yopox/bevy_text_mode/main/assets/promo.png" />
</p>

> `bevy_text_mode` adds a `TextModeTextureAtlasSprite` component with configurable background and foreground colors.
> `bevy_text_mode` adds a `TextModeSprite` component with configurable background and foreground colors.
It makes it easy to use text mode tilesets such as [MRMOTEXT](https://mrmotarius.itch.io/mrmotext).

```rust
pub struct TextModeTextureAtlasSprite {
pub struct TextModeSprite {
pub bg: Color,
pub fg: Color,
pub alpha: f32,
pub index: usize,
pub flip_x: bool,
pub flip_y: bool,
pub rotation: u8,
pub custom_size: Option<Vec2>,
pub rect: Option<Rect>,
pub anchor: Anchor,
}
```

## Usage

Spawn a `TextModeSpriteSheetBundle` with desired background and foreground colors.
Spawn a `TextModeSpriteBundle` with desired background and foreground colors.

## Compatible Bevy versions

| `bevy_text_mode` | `bevy` |
|:----------------:|:------:|
| 0.3.0 | 0.12.1 |
| 0.3.0 | 0.13 |
| 0.2.0 | 0.11 |
| 0.1.1 | 0.10 |
155 changes: 155 additions & 0 deletions src/computed_text_mode_slices.rs
@@ -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);
}
}
}
8 changes: 5 additions & 3 deletions src/lib.rs
@@ -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;

0 comments on commit 2fa04da

Please sign in to comment.