
# 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>
154 lines
5.0 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|