-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
1 parent
6d3766a
commit 9e93770
Showing
6 changed files
with
587 additions
and
557 deletions.
There are no files selected for viewing
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,87 @@ | ||
use super::{ImageBindGroups, SpriteBatch, SpriteMeta}; | ||
use bevy_asset::Handle; | ||
use bevy_ecs::prelude::*; | ||
use bevy_ecs::system::{ | ||
lifetimeless::{Read, SQuery, SRes}, | ||
SystemParamItem, | ||
}; | ||
use bevy_render::{ | ||
render_phase::{ | ||
BatchedPhaseItem, EntityRenderCommand, RenderCommand, RenderCommandResult, SetItemPipeline, | ||
TrackedRenderPass, | ||
}, | ||
view::ViewUniformOffset, | ||
}; | ||
|
||
pub type DrawSprite = ( | ||
SetItemPipeline, | ||
SetSpriteViewBindGroup<0>, | ||
SetSpriteTextureBindGroup<1>, | ||
DrawSpriteBatch, | ||
); | ||
|
||
pub struct SetSpriteViewBindGroup<const I: usize>; | ||
impl<const I: usize> EntityRenderCommand for SetSpriteViewBindGroup<I> { | ||
type Param = (SRes<SpriteMeta>, SQuery<Read<ViewUniformOffset>>); | ||
|
||
fn render<'w>( | ||
view: Entity, | ||
_item: Entity, | ||
(sprite_meta, view_query): SystemParamItem<'w, '_, Self::Param>, | ||
pass: &mut TrackedRenderPass<'w>, | ||
) -> RenderCommandResult { | ||
let view_uniform = view_query.get(view).unwrap(); | ||
pass.set_bind_group( | ||
I, | ||
sprite_meta.into_inner().view_bind_group.as_ref().unwrap(), | ||
&[view_uniform.offset], | ||
); | ||
RenderCommandResult::Success | ||
} | ||
} | ||
pub struct SetSpriteTextureBindGroup<const I: usize>; | ||
impl<const I: usize> EntityRenderCommand for SetSpriteTextureBindGroup<I> { | ||
type Param = (SRes<ImageBindGroups>, SQuery<Read<SpriteBatch>>); | ||
|
||
fn render<'w>( | ||
_view: Entity, | ||
item: Entity, | ||
(image_bind_groups, query_batch): SystemParamItem<'w, '_, Self::Param>, | ||
pass: &mut TrackedRenderPass<'w>, | ||
) -> RenderCommandResult { | ||
let sprite_batch = query_batch.get(item).unwrap(); | ||
let image_bind_groups = image_bind_groups.into_inner(); | ||
|
||
pass.set_bind_group( | ||
I, | ||
image_bind_groups | ||
.values | ||
.get(&Handle::weak(sprite_batch.image_handle_id)) | ||
.unwrap(), | ||
&[], | ||
); | ||
RenderCommandResult::Success | ||
} | ||
} | ||
|
||
pub struct DrawSpriteBatch; | ||
impl<P: BatchedPhaseItem> RenderCommand<P> for DrawSpriteBatch { | ||
type Param = (SRes<SpriteMeta>, SQuery<Read<SpriteBatch>>); | ||
|
||
fn render<'w>( | ||
_view: Entity, | ||
item: &P, | ||
(sprite_meta, query_batch): SystemParamItem<'w, '_, Self::Param>, | ||
pass: &mut TrackedRenderPass<'w>, | ||
) -> RenderCommandResult { | ||
let sprite_batch = query_batch.get(item.entity()).unwrap(); | ||
let sprite_meta = sprite_meta.into_inner(); | ||
if sprite_batch.colored { | ||
pass.set_vertex_buffer(0, sprite_meta.colored_vertices.buffer().unwrap().slice(..)); | ||
} else { | ||
pass.set_vertex_buffer(0, sprite_meta.vertices.buffer().unwrap().slice(..)); | ||
} | ||
pass.draw(item.batch_range().as_ref().unwrap().clone(), 0..1); | ||
RenderCommandResult::Success | ||
} | ||
} |
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,120 @@ | ||
use crate::{Sprite, TextureAtlas, TextureAtlasSprite}; | ||
use bevy_asset::{AssetEvent, Assets, Handle, HandleId}; | ||
use bevy_ecs::prelude::*; | ||
use bevy_math::{Rect, Vec2}; | ||
use bevy_render::prelude::{Color, ComputedVisibility, Image}; | ||
use bevy_render::Extract; | ||
use bevy_transform::prelude::GlobalTransform; | ||
|
||
#[derive(Clone, Copy)] | ||
pub struct ExtractedSprite { | ||
pub entity: Entity, | ||
pub transform: GlobalTransform, | ||
pub color: Color, | ||
/// Select an area of the texture | ||
pub rect: Option<Rect>, | ||
/// Change the on-screen size of the sprite | ||
pub custom_size: Option<Vec2>, | ||
/// Handle to the `Image` of this sprite | ||
/// PERF: storing a `HandleId` instead of `Handle<Image>` enables some optimizations (`ExtractedSprite` becomes `Copy` and doesn't need to be dropped) | ||
pub image_handle_id: HandleId, | ||
pub flip_x: bool, | ||
pub flip_y: bool, | ||
pub anchor: Vec2, | ||
} | ||
|
||
#[derive(Resource, Default)] | ||
pub struct ExtractedSprites { | ||
pub sprites: Vec<ExtractedSprite>, | ||
} | ||
|
||
#[derive(Resource, Default)] | ||
pub struct SpriteAssetEvents { | ||
pub images: Vec<AssetEvent<Image>>, | ||
} | ||
|
||
pub fn extract_sprite_events( | ||
mut events: ResMut<SpriteAssetEvents>, | ||
mut image_events: Extract<EventReader<AssetEvent<Image>>>, | ||
) { | ||
let SpriteAssetEvents { ref mut images } = *events; | ||
images.clear(); | ||
|
||
for image in image_events.iter() { | ||
// AssetEvent: !Clone | ||
images.push(match image { | ||
AssetEvent::Created { handle } => AssetEvent::Created { | ||
handle: handle.clone_weak(), | ||
}, | ||
AssetEvent::Modified { handle } => AssetEvent::Modified { | ||
handle: handle.clone_weak(), | ||
}, | ||
AssetEvent::Removed { handle } => AssetEvent::Removed { | ||
handle: handle.clone_weak(), | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
pub fn extract_sprites( | ||
mut extracted_sprites: ResMut<ExtractedSprites>, | ||
texture_atlases: Extract<Res<Assets<TextureAtlas>>>, | ||
sprite_query: Extract< | ||
Query<( | ||
Entity, | ||
&ComputedVisibility, | ||
&Sprite, | ||
&GlobalTransform, | ||
&Handle<Image>, | ||
)>, | ||
>, | ||
atlas_query: Extract< | ||
Query<( | ||
Entity, | ||
&ComputedVisibility, | ||
&TextureAtlasSprite, | ||
&GlobalTransform, | ||
&Handle<TextureAtlas>, | ||
)>, | ||
>, | ||
) { | ||
for (entity, visibility, sprite, transform, handle) in sprite_query.iter() { | ||
if !visibility.is_visible() { | ||
continue; | ||
} | ||
// PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive | ||
extracted_sprites.sprites.push(ExtractedSprite { | ||
entity, | ||
color: sprite.color, | ||
transform: *transform, | ||
rect: sprite.rect, | ||
// Pass the custom size | ||
custom_size: sprite.custom_size, | ||
flip_x: sprite.flip_x, | ||
flip_y: sprite.flip_y, | ||
image_handle_id: handle.id(), | ||
anchor: sprite.anchor.as_vec(), | ||
}); | ||
} | ||
for (entity, visibility, atlas_sprite, transform, texture_atlas_handle) in atlas_query.iter() { | ||
if !visibility.is_visible() { | ||
continue; | ||
} | ||
if let Some(texture_atlas) = texture_atlases.get(texture_atlas_handle) { | ||
let rect = Some(texture_atlas.textures[atlas_sprite.index]); | ||
extracted_sprites.sprites.push(ExtractedSprite { | ||
entity, | ||
color: atlas_sprite.color, | ||
transform: *transform, | ||
// Select the area in the texture atlas | ||
rect, | ||
// Pass the custom size | ||
custom_size: atlas_sprite.custom_size, | ||
flip_x: atlas_sprite.flip_x, | ||
flip_y: atlas_sprite.flip_y, | ||
image_handle_id: texture_atlas.texture.id(), | ||
anchor: atlas_sprite.anchor.as_vec(), | ||
}); | ||
} | ||
} | ||
} |
Oops, something went wrong.