bevy/crates/bevy_sprite/src/lib.rs
Edgar Geier f18f28874a
Allow tuples and single plugins in add_plugins, deprecate add_plugin (#8097)
# Objective

- Better consistency with `add_systems`.
- Deprecating `add_plugin` in favor of a more powerful `add_plugins`.
- Allow passing `Plugin` to `add_plugins`.
- Allow passing tuples to `add_plugins`.

## Solution

- `App::add_plugins` now takes an `impl Plugins` parameter.
- `App::add_plugin` is deprecated.
- `Plugins` is a new sealed trait that is only implemented for `Plugin`,
`PluginGroup` and tuples over `Plugins`.
- All examples, benchmarks and tests are changed to use `add_plugins`,
using tuples where appropriate.

---

## Changelog

### Changed

- `App::add_plugins` now accepts all types that implement `Plugins`,
which is implemented for:
  - Types that implement `Plugin`.
  - Types that implement `PluginGroup`.
  - Tuples (up to 16 elements) over types that implement `Plugins`.
- Deprecated `App::add_plugin` in favor of `App::add_plugins`.

## Migration Guide

- Replace `app.add_plugin(plugin)` calls with `app.add_plugins(plugin)`.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-21 20:51:03 +00:00

154 lines
5.0 KiB
Rust

#![allow(clippy::type_complexity)]
mod bundle;
mod dynamic_texture_atlas_builder;
mod mesh2d;
mod render;
mod sprite;
mod texture_atlas;
mod texture_atlas_builder;
pub mod collide_aabb;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
bundle::{SpriteBundle, SpriteSheetBundle},
sprite::Sprite,
texture_atlas::{TextureAtlas, TextureAtlasSprite},
ColorMaterial, ColorMesh2dBundle, TextureAtlasBuilder,
};
}
pub use bundle::*;
pub use dynamic_texture_atlas_builder::*;
pub use mesh2d::*;
pub use render::*;
pub use sprite::*;
pub use texture_atlas::*;
pub use texture_atlas_builder::*;
use bevy_app::prelude::*;
use bevy_asset::{AddAsset, Assets, Handle, HandleUntyped};
use bevy_core_pipeline::core_2d::Transparent2d;
use bevy_ecs::prelude::*;
use bevy_reflect::TypeUuid;
use bevy_render::{
mesh::Mesh,
primitives::Aabb,
render_phase::AddRenderCommand,
render_resource::{Shader, SpecializedRenderPipelines},
texture::Image,
view::{NoFrustumCulling, VisibilitySystems},
ExtractSchedule, Render, RenderApp, RenderSet,
};
#[derive(Default)]
pub struct SpritePlugin;
pub const SPRITE_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2763343953151597127);
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub enum SpriteSystem {
ExtractSprites,
}
impl Plugin for SpritePlugin {
fn build(&self, app: &mut App) {
let mut shaders = app.world.resource_mut::<Assets<Shader>>();
let sprite_shader = Shader::from_wgsl(include_str!("render/sprite.wgsl"));
shaders.set_untracked(SPRITE_SHADER_HANDLE, sprite_shader);
app.add_asset::<TextureAtlas>()
.register_asset_reflect::<TextureAtlas>()
.register_type::<Sprite>()
.register_type::<TextureAtlasSprite>()
.register_type::<Anchor>()
.register_type::<Mesh2dHandle>()
.add_plugins((Mesh2dRenderPlugin, ColorMaterialPlugin))
.add_systems(
PostUpdate,
calculate_bounds_2d.in_set(VisibilitySystems::CalculateBounds),
);
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app
.init_resource::<ImageBindGroups>()
.init_resource::<SpecializedRenderPipelines<SpritePipeline>>()
.init_resource::<SpriteMeta>()
.init_resource::<ExtractedSprites>()
.init_resource::<SpriteAssetEvents>()
.add_render_command::<Transparent2d, DrawSprite>()
.add_systems(
ExtractSchedule,
(
extract_sprites.in_set(SpriteSystem::ExtractSprites),
extract_sprite_events,
),
)
.add_systems(
Render,
queue_sprites
.in_set(RenderSet::Queue)
.ambiguous_with(queue_material2d_meshes::<ColorMaterial>),
);
};
}
fn finish(&self, app: &mut App) {
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.init_resource::<SpritePipeline>();
}
}
}
pub fn calculate_bounds_2d(
mut commands: Commands,
meshes: Res<Assets<Mesh>>,
images: Res<Assets<Image>>,
atlases: Res<Assets<TextureAtlas>>,
meshes_without_aabb: Query<(Entity, &Mesh2dHandle), (Without<Aabb>, Without<NoFrustumCulling>)>,
sprites_without_aabb: Query<
(Entity, &Sprite, &Handle<Image>),
(Without<Aabb>, Without<NoFrustumCulling>),
>,
atlases_without_aabb: Query<
(Entity, &TextureAtlasSprite, &Handle<TextureAtlas>),
(Without<Aabb>, Without<NoFrustumCulling>),
>,
) {
for (entity, mesh_handle) in &meshes_without_aabb {
if let Some(mesh) = meshes.get(&mesh_handle.0) {
if let Some(aabb) = mesh.compute_aabb() {
commands.entity(entity).insert(aabb);
}
}
}
for (entity, sprite, texture_handle) in &sprites_without_aabb {
if let Some(size) = sprite
.custom_size
.or_else(|| images.get(texture_handle).map(|image| image.size()))
{
let aabb = Aabb {
center: (-sprite.anchor.as_vec() * size).extend(0.0).into(),
half_extents: (0.5 * size).extend(0.0).into(),
};
commands.entity(entity).insert(aabb);
}
}
for (entity, atlas_sprite, atlas_handle) in &atlases_without_aabb {
if let Some(size) = atlas_sprite.custom_size.or_else(|| {
atlases
.get(atlas_handle)
.and_then(|atlas| atlas.textures.get(atlas_sprite.index))
.map(|rect| (rect.min - rect.max).abs())
}) {
let aabb = Aabb {
center: (-atlas_sprite.anchor.as_vec() * size).extend(0.0).into(),
half_extents: (0.5 * size).extend(0.0).into(),
};
commands.entity(entity).insert(aabb);
}
}
}