Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract sprites into a Vec #17619

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ pub struct Transparent2d {
pub pipeline: CachedRenderPipelineId,
pub draw_function: DrawFunctionId,
pub batch_range: Range<u32>,
pub extracted_index: usize,
pub extra_index: PhaseItemExtraIndex,
/// Whether the mesh in question is indexed (uses an index buffer in
/// addition to its vertex buffer).
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_gizmos/src/pipeline_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ fn queue_line_gizmos_2d(
sort_key: FloatOrd(f32::INFINITY),
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::None,
extracted_index: usize::MAX,
indexed: false,
});
}
Expand All @@ -362,6 +363,7 @@ fn queue_line_gizmos_2d(
sort_key: FloatOrd(f32::INFINITY),
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::None,
extracted_index: usize::MAX,
indexed: false,
});
}
Expand Down Expand Up @@ -421,6 +423,7 @@ fn queue_line_joint_gizmos_2d(
sort_key: FloatOrd(f32::INFINITY),
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::None,
extracted_index: usize::MAX,
indexed: false,
});
}
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_sprite/src/mesh2d/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
// Batching is done in batch_and_prepare_render_phase
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::None,
extracted_index: usize::MAX,
indexed: mesh.indexed(),
});
}
Expand Down
77 changes: 39 additions & 38 deletions crates/bevy_sprite/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use bevy_ecs::{
use bevy_image::{BevyDefault, Image, ImageSampler, TextureAtlasLayout, TextureFormatPixelInfo};
use bevy_math::{Affine3A, FloatOrd, Quat, Rect, Vec2, Vec4};
use bevy_platform_support::collections::HashMap;
use bevy_render::sync_world::MainEntity;
use bevy_render::view::RenderVisibleEntities;
use bevy_render::{
render_asset::RenderAssets,
Expand All @@ -31,7 +30,7 @@ use bevy_render::{
*,
},
renderer::{RenderDevice, RenderQueue},
sync_world::{RenderEntity, TemporaryRenderEntity},
sync_world::RenderEntity,
texture::{DefaultImageSampler, FallbackImage, GpuImage},
view::{
ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms,
Expand Down Expand Up @@ -338,13 +337,15 @@ pub struct ExtractedSprite {
pub anchor: Vec2,
/// For cases where additional [`ExtractedSprites`] are created during extraction, this stores the
/// entity that caused that creation for use in determining visibility.
pub original_entity: Option<Entity>,
pub original_entity: Entity,
pub scaling_mode: Option<ScalingMode>,
pub render_entity: Entity,
}

#[derive(Resource, Default)]
pub struct ExtractedSprites {
pub sprites: HashMap<(Entity, MainEntity), ExtractedSprite>,
//pub sprites: HashMap<(Entity, MainEntity), ExtractedSprite>,
pub sprites: Vec<ExtractedSprite>,
}

#[derive(Resource, Default)]
Expand Down Expand Up @@ -387,19 +388,12 @@ pub fn extract_sprites(
}

if let Some(slices) = slices {
extracted_sprites.sprites.extend(
slices
.extract_sprites(transform, original_entity, sprite)
.map(|e| {
(
(
commands.spawn(TemporaryRenderEntity).id(),
original_entity.into(),
),
e,
)
}),
);
extracted_sprites.sprites.extend(slices.extract_sprites(
&mut commands,
transform,
original_entity,
sprite,
));
} else {
let atlas_rect = sprite
.texture_atlas
Expand All @@ -418,22 +412,20 @@ pub fn extract_sprites(
};

// 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.insert(
(entity, original_entity.into()),
ExtractedSprite {
color: sprite.color.into(),
transform: *transform,
rect,
// Pass the custom size
custom_size: sprite.custom_size,
flip_x: sprite.flip_x,
flip_y: sprite.flip_y,
image_handle_id: sprite.image.id(),
anchor: sprite.anchor.as_vec(),
original_entity: Some(original_entity),
scaling_mode: sprite.image_mode.scale(),
},
);
extracted_sprites.sprites.push(ExtractedSprite {
render_entity: entity,
color: sprite.color.into(),
transform: *transform,
rect,
// Pass the custom size
custom_size: sprite.custom_size,
flip_x: sprite.flip_x,
flip_y: sprite.flip_y,
image_handle_id: sprite.image.id(),
anchor: sprite.anchor.as_vec(),
original_entity,
scaling_mode: sprite.image_mode.scale(),
});
}
}
}
Expand Down Expand Up @@ -557,10 +549,10 @@ pub fn queue_sprites(
.items
.reserve(extracted_sprites.sprites.len());

for ((entity, main_entity), extracted_sprite) in extracted_sprites.sprites.iter() {
let index = extracted_sprite.original_entity.unwrap_or(*entity).index();
for (index, extracted_sprite) in extracted_sprites.sprites.iter().enumerate() {
let view_index = extracted_sprite.original_entity.index();

if !view_entities.contains(index as usize) {
if !view_entities.contains(view_index as usize) {
continue;
}

Expand All @@ -571,11 +563,15 @@ pub fn queue_sprites(
transparent_phase.add(Transparent2d {
draw_function: draw_sprite_function,
pipeline,
entity: (*entity, *main_entity),
entity: (
extracted_sprite.render_entity,
extracted_sprite.original_entity.into(),
),
sort_key,
// batch_range and dynamic_offset will be calculated in prepare_sprites
batch_range: 0..0,
extra_index: PhaseItemExtraIndex::None,
extracted_index: index,
indexed: true,
});
}
Expand Down Expand Up @@ -660,7 +656,12 @@ pub fn prepare_sprite_image_bind_groups(
// Compatible items share the same entity.
for item_index in 0..transparent_phase.items.len() {
let item = &transparent_phase.items[item_index];
let Some(extracted_sprite) = extracted_sprites.sprites.get(&item.entity) else {

let Some(extracted_sprite) = extracted_sprites
.sprites
.get(item.extracted_index)
.filter(|extracted_sprite| extracted_sprite.render_entity == item.entity())
else {
// If there is a phase item that is not a sprite, then we must start a new
// batch to draw the other phase item(s) and to respect draw order. This can be
// done by invalidating the batch_image_handle
Expand Down
9 changes: 6 additions & 3 deletions crates/bevy_sprite/src/texture_slice/computed_slices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bevy_ecs::prelude::*;
use bevy_image::Image;
use bevy_math::{Rect, Vec2};
use bevy_platform_support::collections::HashSet;
use bevy_render::sync_world::TemporaryRenderEntity;
use bevy_transform::prelude::*;

/// Component storing texture slices for tiled or sliced sprite entities
Expand All @@ -24,12 +25,13 @@ impl ComputedTextureSlices {
/// * `sprite` - The sprite component
/// * `handle` - The sprite texture handle
#[must_use]
pub(crate) fn extract_sprites<'a>(
pub(crate) fn extract_sprites<'a, 'w, 's>(
&'a self,
commands: &'a mut Commands<'w, 's>,
transform: &'a GlobalTransform,
original_entity: Entity,
sprite: &'a Sprite,
) -> impl ExactSizeIterator<Item = ExtractedSprite> + 'a {
) -> impl ExactSizeIterator<Item = ExtractedSprite> + 'a + use<'a, 'w, 's> {
let mut flip = Vec2::ONE;
let [mut flip_x, mut flip_y] = [false; 2];
if sprite.flip_x {
Expand All @@ -44,7 +46,8 @@ impl ComputedTextureSlices {
let offset = (slice.offset * flip).extend(0.0);
let transform = transform.mul_transform(Transform::from_translation(offset));
ExtractedSprite {
original_entity: Some(original_entity),
render_entity: commands.spawn(TemporaryRenderEntity).id(),
original_entity,
color: sprite.color.into(),
transform,
rect: Some(slice.texture_rect),
Expand Down
31 changes: 13 additions & 18 deletions crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,24 +198,19 @@ pub fn extract_text2d_sprite(
}
let atlas = texture_atlases.get(&atlas_info.texture_atlas).unwrap();

extracted_sprites.sprites.insert(
(
commands.spawn(TemporaryRenderEntity).id(),
original_entity.into(),
),
ExtractedSprite {
transform: transform * GlobalTransform::from_translation(position.extend(0.)),
color,
rect: Some(atlas.textures[atlas_info.location.glyph_index].as_rect()),
custom_size: None,
image_handle_id: atlas_info.texture.id(),
flip_x: false,
flip_y: false,
anchor: Anchor::Center.as_vec(),
original_entity: Some(original_entity),
scaling_mode: None,
},
);
extracted_sprites.sprites.push(ExtractedSprite {
render_entity: commands.spawn(TemporaryRenderEntity).id(),
transform: transform * GlobalTransform::from_translation(position.extend(0.)),
color,
rect: Some(atlas.textures[atlas_info.location.glyph_index].as_rect()),
custom_size: None,
image_handle_id: atlas_info.texture.id(),
flip_x: false,
flip_y: false,
anchor: Anchor::Center.as_vec(),
original_entity,
scaling_mode: None,
});
}
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/2d/mesh2d_manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ pub fn queue_colored_mesh2d(
// This material is not batched
batch_range: 0..1,
extra_index: PhaseItemExtraIndex::None,
extracted_index: usize::MAX,
indexed: mesh.indexed(),
});
}
Expand Down