1use core::ops::Range;
2
3use bevy_asset::{load_embedded_asset, AssetEvent, AssetId, AssetServer, Handle};
4use bevy_camera::CompositingSpace;
5use bevy_color::{ColorToComponents, LinearRgba};
6use bevy_core_pipeline::{
7 core_2d::{Transparent2d, CORE_2D_DEPTH_FORMAT},
8 tonemapping::{
9 get_lut_bind_group_layout_entries, get_lut_bindings, DebandDither, Tonemapping,
10 TonemappingLuts,
11 },
12};
13use bevy_derive::{Deref, DerefMut};
14use bevy_ecs::{
15 prelude::*,
16 query::ROQueryItem,
17 system::{lifetimeless::*, SystemParamItem},
18};
19use bevy_image::Image;
20use bevy_math::{Affine3A, FloatOrd, Quat, Rect, Vec2, Vec4};
21use bevy_mesh::VertexBufferLayout;
22use bevy_platform::collections::HashMap;
23use bevy_render::{
24 camera::ExtractedCamera,
25 view::{RenderVisibleEntities, ResolvedCompositingSpace, RetainedViewEntity},
26};
27use bevy_render::{
28 render_asset::RenderAssets,
29 render_phase::{
30 DrawFunctions, PhaseItem, PhaseItemExtraIndex, RenderCommand, RenderCommandResult,
31 SetItemPipeline, TrackedRenderPass, ViewSortedRenderPhases,
32 },
33 render_resource::{
34 binding_types::{sampler, texture_2d, uniform_buffer},
35 *,
36 },
37 renderer::{RenderDevice, RenderQueue},
38 texture::{FallbackImage, GpuImage},
39 view::{
40 texture_format_from_code, texture_format_to_code, ExtractedView, Msaa, ViewUniform,
41 ViewUniformOffset, ViewUniforms,
42 },
43 Extract,
44};
45use bevy_shader::{Shader, ShaderDefVal};
46use bevy_sprite::Sprite;
47use bevy_transform::components::GlobalTransform;
48use bevy_utils::default;
49use bytemuck::{Pod, Zeroable};
50use fixedbitset::FixedBitSet;
51
52#[derive(impl bevy_ecs::component::Component for SpritePipeline where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<SpritePipeline>()
{
id
} else {
required_components.components_registrator().register_component::<SpritePipeline>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for SpritePipeline where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource)]
53pub struct SpritePipeline {
54 view_layout: BindGroupLayoutDescriptor,
55 material_layout: BindGroupLayoutDescriptor,
56 shader: Handle<Shader>,
57}
58
59pub fn init_sprite_pipeline(mut commands: Commands, asset_server: Res<AssetServer>) {
60 let tonemapping_lut_entries = get_lut_bind_group_layout_entries();
61 let view_layout = BindGroupLayoutDescriptor::new(
62 "sprite_view_layout",
63 &BindGroupLayoutEntries::sequential(
64 ShaderStages::VERTEX_FRAGMENT,
65 (
66 uniform_buffer::<ViewUniform>(true),
67 tonemapping_lut_entries[0].visibility(ShaderStages::FRAGMENT),
68 tonemapping_lut_entries[1].visibility(ShaderStages::FRAGMENT),
69 ),
70 ),
71 );
72
73 let material_layout = BindGroupLayoutDescriptor::new(
74 "sprite_material_layout",
75 &BindGroupLayoutEntries::sequential(
76 ShaderStages::FRAGMENT,
77 (
78 texture_2d(TextureSampleType::Float { filterable: true }),
79 sampler(SamplerBindingType::Filtering),
80 ),
81 ),
82 );
83
84 commands.insert_resource(SpritePipeline {
85 view_layout,
86 material_layout,
87 shader: {
let (path, asset_server) =
{
let path =
{
{
let crate_name =
"bevy_sprite_render::render".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/render/mod.rs".as_ref(),
"sprite.wesl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(asset_server.as_ref());
(path, asset_server)
};
asset_server.load(path)
}load_embedded_asset!(asset_server.as_ref(), "sprite.wesl"),
88 });
89}
90
91#[repr(transparent)]
pub struct SpritePipelineKey(<SpritePipelineKey as
::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for SpritePipelineKey {
}
#[automatically_derived]impl ::core::clone::Clone for SpritePipelineKey {
#[inline]
fn clone(&self) -> Self {
let _:
::core::clone::AssertParamIsClone<<SpritePipelineKey as
::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
#[automatically_derived]impl ::core::marker::Copy for SpritePipelineKey { }
#[automatically_derived]impl ::core::fmt::Debug for SpritePipelineKey {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"SpritePipelineKey", &&self.0)
}
}
#[automatically_derived]impl ::core::marker::StructuralPartialEq for
SpritePipelineKey {
}
#[automatically_derived]impl ::core::cmp::PartialEq for SpritePipelineKey {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]impl ::core::cmp::Eq for SpritePipelineKey {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<<SpritePipelineKey as
::bitflags::__private::PublicFlags>::Internal>;
}
}
#[automatically_derived]impl ::core::hash::Hash for SpritePipelineKey {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl SpritePipelineKey {
pub const NONE: Self = Self::from_bits_retain(0);
pub const TONEMAP_IN_SHADER: Self = Self::from_bits_retain(1 << 0);
pub const DEBAND_DITHER: Self = Self::from_bits_retain(1 << 1);
pub const SRGB_COMPOSITING: Self = Self::from_bits_retain(1 << 2);
pub const OKLAB_COMPOSITING: Self = Self::from_bits_retain(1 << 3);
pub const COLOR_TARGET_FORMAT_RESERVED_BITS: Self =
Self::from_bits_retain(Self::COLOR_TARGET_FORMAT_MASK_BITS <<
Self::COLOR_TARGET_FORMAT_SHIFT_BITS);
pub const MSAA_RESERVED_BITS: Self =
Self::from_bits_retain(Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS);
pub const TONEMAP_METHOD_RESERVED_BITS: Self =
Self::from_bits_retain(Self::TONEMAP_METHOD_MASK_BITS <<
Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_LINEAR: Self =
Self::from_bits_retain(0 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_REINHARD: Self =
Self::from_bits_retain(1 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_REINHARD_LUMINANCE: Self =
Self::from_bits_retain(2 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_ACES_FITTED: Self =
Self::from_bits_retain(3 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_AGX: Self =
Self::from_bits_retain(4 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM: Self =
Self::from_bits_retain(5 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_TONY_MC_MAPFACE: Self =
Self::from_bits_retain(6 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_BLENDER_FILMIC: Self =
Self::from_bits_retain(7 << Self::TONEMAP_METHOD_SHIFT_BITS);
pub const TONEMAP_METHOD_PBR_NEUTRAL: Self =
Self::from_bits_retain(8 << Self::TONEMAP_METHOD_SHIFT_BITS);
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
impl ::bitflags::Flags for SpritePipelineKey {
const FLAGS: &'static [::bitflags::Flag<SpritePipelineKey>] =
{
mod __bitflags_flag_names {
#[allow(unused_imports)]
use super::*;
pub(super) const NONE: &'static str = "NONE";
pub(super) const TONEMAP_IN_SHADER: &'static str =
"TONEMAP_IN_SHADER";
pub(super) const DEBAND_DITHER: &'static str =
"DEBAND_DITHER";
pub(super) const SRGB_COMPOSITING: &'static str =
"SRGB_COMPOSITING";
pub(super) const OKLAB_COMPOSITING: &'static str =
"OKLAB_COMPOSITING";
pub(super) const COLOR_TARGET_FORMAT_RESERVED_BITS:
&'static str =
"COLOR_TARGET_FORMAT_RESERVED_BITS";
pub(super) const MSAA_RESERVED_BITS: &'static str =
"MSAA_RESERVED_BITS";
pub(super) const TONEMAP_METHOD_RESERVED_BITS: &'static str =
"TONEMAP_METHOD_RESERVED_BITS";
pub(super) const TONEMAP_METHOD_LINEAR: &'static str =
"TONEMAP_METHOD_LINEAR";
pub(super) const TONEMAP_METHOD_REINHARD: &'static str =
"TONEMAP_METHOD_REINHARD";
pub(super) const TONEMAP_METHOD_REINHARD_LUMINANCE:
&'static str =
"TONEMAP_METHOD_REINHARD_LUMINANCE";
pub(super) const TONEMAP_METHOD_ACES_FITTED: &'static str =
"TONEMAP_METHOD_ACES_FITTED";
pub(super) const TONEMAP_METHOD_AGX: &'static str =
"TONEMAP_METHOD_AGX";
pub(super) const
TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM:
&'static str =
"TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM";
pub(super) const TONEMAP_METHOD_TONY_MC_MAPFACE: &'static str
=
"TONEMAP_METHOD_TONY_MC_MAPFACE";
pub(super) const TONEMAP_METHOD_BLENDER_FILMIC: &'static str =
"TONEMAP_METHOD_BLENDER_FILMIC";
pub(super) const TONEMAP_METHOD_PBR_NEUTRAL: &'static str =
"TONEMAP_METHOD_PBR_NEUTRAL";
}
&[{
::bitflags::Flag::new(__bitflags_flag_names::NONE,
SpritePipelineKey::NONE)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_IN_SHADER,
SpritePipelineKey::TONEMAP_IN_SHADER)
},
{
::bitflags::Flag::new(__bitflags_flag_names::DEBAND_DITHER,
SpritePipelineKey::DEBAND_DITHER)
},
{
::bitflags::Flag::new(__bitflags_flag_names::SRGB_COMPOSITING,
SpritePipelineKey::SRGB_COMPOSITING)
},
{
::bitflags::Flag::new(__bitflags_flag_names::OKLAB_COMPOSITING,
SpritePipelineKey::OKLAB_COMPOSITING)
},
{
::bitflags::Flag::new(__bitflags_flag_names::COLOR_TARGET_FORMAT_RESERVED_BITS,
SpritePipelineKey::COLOR_TARGET_FORMAT_RESERVED_BITS)
},
{
::bitflags::Flag::new(__bitflags_flag_names::MSAA_RESERVED_BITS,
SpritePipelineKey::MSAA_RESERVED_BITS)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_RESERVED_BITS,
SpritePipelineKey::TONEMAP_METHOD_RESERVED_BITS)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_LINEAR,
SpritePipelineKey::TONEMAP_METHOD_LINEAR)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_REINHARD,
SpritePipelineKey::TONEMAP_METHOD_REINHARD)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_REINHARD_LUMINANCE,
SpritePipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_ACES_FITTED,
SpritePipelineKey::TONEMAP_METHOD_ACES_FITTED)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_AGX,
SpritePipelineKey::TONEMAP_METHOD_AGX)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM,
SpritePipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_TONY_MC_MAPFACE,
SpritePipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_BLENDER_FILMIC,
SpritePipelineKey::TONEMAP_METHOD_BLENDER_FILMIC)
},
{
::bitflags::Flag::new(__bitflags_flag_names::TONEMAP_METHOD_PBR_NEUTRAL,
SpritePipelineKey::TONEMAP_METHOD_PBR_NEUTRAL)
}]
};
type Bits = u32;
fn bits(&self) -> u32 { SpritePipelineKey::bits(self) }
fn from_bits_retain(bits: u32) -> SpritePipelineKey {
SpritePipelineKey::from_bits_retain(bits)
}
fn all_named() -> SpritePipelineKey {
const ALL_NAMED: u32 =
{
let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
{
{
let flag =
&<SpritePipelineKey as ::bitflags::Flags>::FLAGS[i];
if flag.is_named() {
truncated = truncated | flag.value().bits();
}
i += 1;
}
};
let _ = i;
truncated
};
SpritePipelineKey::from_bits_retain(ALL_NAMED)
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
pub struct InternalBitFlags(u32);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self,
other))
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::bitflags::__private::PublicFlags for SpritePipelineKey {
type Primitive = u32;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u32 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&SpritePipelineKey(*self), f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<SpritePipelineKey>(s).map(|flags|
flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u32> for
InternalBitFlags {
fn as_ref(&self) -> &u32 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u32> for
InternalBitFlags {
fn from(bits: u32) -> Self { Self::from_bits_retain(bits) }
}
impl InternalBitFlags {
#[inline]
pub const fn empty() -> Self {
Self(<u32 as ::bitflags::Bits>::EMPTY)
}
#[inline]
pub const fn all() -> Self {
const ALL: InternalBitFlags =
{
let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
let mut _i = 0;
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
{
{
truncated |=
<SpritePipelineKey as
::bitflags::Flags>::FLAGS[_i].value().bits();
_i += 1;
}
};
InternalBitFlags(truncated)
};
ALL
}
#[inline]
pub const fn bits(&self) -> u32 { self.0 }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(bits & Self::all().0)
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
mod __bitflags_flag_names {
#[allow(unused_imports)]
use super::*;
pub(super) const NONE: &'static str = "NONE";
pub(super) const TONEMAP_IN_SHADER: &'static str =
"TONEMAP_IN_SHADER";
pub(super) const DEBAND_DITHER: &'static str =
"DEBAND_DITHER";
pub(super) const SRGB_COMPOSITING: &'static str =
"SRGB_COMPOSITING";
pub(super) const OKLAB_COMPOSITING: &'static str =
"OKLAB_COMPOSITING";
pub(super) const COLOR_TARGET_FORMAT_RESERVED_BITS:
&'static str =
"COLOR_TARGET_FORMAT_RESERVED_BITS";
pub(super) const MSAA_RESERVED_BITS: &'static str =
"MSAA_RESERVED_BITS";
pub(super) const TONEMAP_METHOD_RESERVED_BITS: &'static str
=
"TONEMAP_METHOD_RESERVED_BITS";
pub(super) const TONEMAP_METHOD_LINEAR: &'static str =
"TONEMAP_METHOD_LINEAR";
pub(super) const TONEMAP_METHOD_REINHARD: &'static str =
"TONEMAP_METHOD_REINHARD";
pub(super) const TONEMAP_METHOD_REINHARD_LUMINANCE:
&'static str =
"TONEMAP_METHOD_REINHARD_LUMINANCE";
pub(super) const TONEMAP_METHOD_ACES_FITTED: &'static str =
"TONEMAP_METHOD_ACES_FITTED";
pub(super) const TONEMAP_METHOD_AGX: &'static str =
"TONEMAP_METHOD_AGX";
pub(super) const
TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM:
&'static str =
"TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM";
pub(super) const TONEMAP_METHOD_TONY_MC_MAPFACE:
&'static str =
"TONEMAP_METHOD_TONY_MC_MAPFACE";
pub(super) const TONEMAP_METHOD_BLENDER_FILMIC: &'static str
=
"TONEMAP_METHOD_BLENDER_FILMIC";
pub(super) const TONEMAP_METHOD_PBR_NEUTRAL: &'static str =
"TONEMAP_METHOD_PBR_NEUTRAL";
}
{
{
if name == __bitflags_flag_names::NONE {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::NONE.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_IN_SHADER {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_IN_SHADER.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::DEBAND_DITHER {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::DEBAND_DITHER.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::SRGB_COMPOSITING {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::SRGB_COMPOSITING.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::OKLAB_COMPOSITING {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::OKLAB_COMPOSITING.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::COLOR_TARGET_FORMAT_RESERVED_BITS {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::COLOR_TARGET_FORMAT_RESERVED_BITS.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::MSAA_RESERVED_BITS {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::MSAA_RESERVED_BITS.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::TONEMAP_METHOD_RESERVED_BITS {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_RESERVED_BITS.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_METHOD_LINEAR {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_LINEAR.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_METHOD_REINHARD {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_REINHARD.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::TONEMAP_METHOD_REINHARD_LUMINANCE {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_METHOD_ACES_FITTED
{
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_ACES_FITTED.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_METHOD_AGX {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_AGX.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
{
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::TONEMAP_METHOD_TONY_MC_MAPFACE {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE.bits()));
}
};
};
{
{
if name ==
__bitflags_flag_names::TONEMAP_METHOD_BLENDER_FILMIC {
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_BLENDER_FILMIC.bits()));
}
};
};
{
{
if name == __bitflags_flag_names::TONEMAP_METHOD_PBR_NEUTRAL
{
return ::bitflags::__private::core::option::Option::Some(Self(SpritePipelineKey::TONEMAP_METHOD_PBR_NEUTRAL.bits()));
}
};
};
let _ = name;
::bitflags::__private::core::option::Option::None
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<SpritePipelineKey> {
::bitflags::iter::Iter::__private_const_new(<SpritePipelineKey
as ::bitflags::Flags>::FLAGS,
SpritePipelineKey::from_bits_retain(self.bits()),
SpritePipelineKey::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<SpritePipelineKey> {
::bitflags::iter::IterNames::__private_const_new(<SpritePipelineKey
as ::bitflags::Flags>::FLAGS,
SpritePipelineKey::from_bits_retain(self.bits()),
SpritePipelineKey::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = SpritePipelineKey;
type IntoIter = ::bitflags::iter::Iter<SpritePipelineKey>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
#[inline]
pub fn bits_mut(&mut self) -> &mut u32 { &mut self.0 }
}
impl ::bitflags::__private::serde::Serialize for InternalBitFlags {
fn serialize<S: ::bitflags::__private::serde::Serializer>(&self,
serializer: S)
->
::bitflags::__private::core::result::Result<S::Ok,
S::Error> {
::bitflags::serde::serialize(&SpritePipelineKey::from_bits_retain(self.bits()),
serializer)
}
}
impl<'de> ::bitflags::__private::serde::Deserialize<'de> for
InternalBitFlags {
fn deserialize<D: ::bitflags::__private::serde::Deserializer<'de>>(deserializer:
D)
->
::bitflags::__private::core::result::Result<Self,
D::Error> {
let flags: SpritePipelineKey =
::bitflags::serde::deserialize(deserializer)?;
::bitflags::__private::core::result::Result::Ok(flags.0)
}
}
impl SpritePipelineKey {
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
#[inline]
pub const fn bits(&self) -> u32 { self.0.bits() }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for SpritePipelineKey {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for SpritePipelineKey {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for SpritePipelineKey
{
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for SpritePipelineKey
{
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for SpritePipelineKey {
type Output = Self;
#[inline]
fn bitor(self, other: SpritePipelineKey) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
SpritePipelineKey {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for SpritePipelineKey {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
SpritePipelineKey {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for SpritePipelineKey {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
SpritePipelineKey {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for SpritePipelineKey {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for SpritePipelineKey
{
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for SpritePipelineKey {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<SpritePipelineKey> for
SpritePipelineKey {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<SpritePipelineKey>
for SpritePipelineKey {
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl SpritePipelineKey {
#[inline]
pub const fn iter(&self)
-> ::bitflags::iter::Iter<SpritePipelineKey> {
::bitflags::iter::Iter::__private_const_new(<SpritePipelineKey
as ::bitflags::Flags>::FLAGS,
SpritePipelineKey::from_bits_retain(self.bits()),
SpritePipelineKey::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<SpritePipelineKey> {
::bitflags::iter::IterNames::__private_const_new(<SpritePipelineKey
as ::bitflags::Flags>::FLAGS,
SpritePipelineKey::from_bits_retain(self.bits()),
SpritePipelineKey::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
SpritePipelineKey {
type Item = SpritePipelineKey;
type IntoIter = ::bitflags::iter::Iter<SpritePipelineKey>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};bitflags::bitflags! {
92 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
93 #[repr(transparent)]
94 pub struct SpritePipelineKey: u32 {
97 const NONE = 0;
98 const TONEMAP_IN_SHADER = 1 << 0;
99 const DEBAND_DITHER = 1 << 1;
100 const SRGB_COMPOSITING = 1 << 2;
101 const OKLAB_COMPOSITING = 1 << 3;
102 const COLOR_TARGET_FORMAT_RESERVED_BITS = Self::COLOR_TARGET_FORMAT_MASK_BITS << Self::COLOR_TARGET_FORMAT_SHIFT_BITS;
103 const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS;
104 const TONEMAP_METHOD_RESERVED_BITS = Self::TONEMAP_METHOD_MASK_BITS << Self::TONEMAP_METHOD_SHIFT_BITS;
105 const TONEMAP_METHOD_LINEAR = 0 << Self::TONEMAP_METHOD_SHIFT_BITS;
106 const TONEMAP_METHOD_REINHARD = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
107 const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
108 const TONEMAP_METHOD_ACES_FITTED = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
109 const TONEMAP_METHOD_AGX = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
110 const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
111 const TONEMAP_METHOD_TONY_MC_MAPFACE = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
112 const TONEMAP_METHOD_BLENDER_FILMIC = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
113 const TONEMAP_METHOD_PBR_NEUTRAL = 8 << Self::TONEMAP_METHOD_SHIFT_BITS;
114
115 }
116}
117
118impl SpritePipelineKey {
119 const COLOR_TARGET_FORMAT_MASK_BITS: u32 = bevy_render::view::COLOR_TARGET_FORMAT_MASK_BITS;
120 const COLOR_TARGET_FORMAT_SHIFT_BITS: u32 = 4;
121 const MSAA_MASK_BITS: u32 = 0b111;
122 const MSAA_SHIFT_BITS: u32 = 32 - Self::MSAA_MASK_BITS.count_ones();
123 const TONEMAP_METHOD_MASK_BITS: u32 = 0b1111;
124 const TONEMAP_METHOD_SHIFT_BITS: u32 =
125 Self::MSAA_SHIFT_BITS - Self::TONEMAP_METHOD_MASK_BITS.count_ones();
126
127 #[inline]
128 pub const fn from_msaa_samples(msaa_samples: u32) -> Self {
129 let msaa_bits =
130 (msaa_samples.trailing_zeros() & Self::MSAA_MASK_BITS) << Self::MSAA_SHIFT_BITS;
131 Self::from_bits_retain(msaa_bits)
132 }
133
134 #[inline]
135 pub const fn msaa_samples(&self) -> u32 {
136 1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
137 }
138
139 #[inline]
141 pub fn from_target_format(format: TextureFormat) -> Self {
142 let code = texture_format_to_code(format)
143 .expect("Texture format is not supported by the pipeline") as u32;
144 Self::from_bits_retain(
145 (code & Self::COLOR_TARGET_FORMAT_MASK_BITS) << Self::COLOR_TARGET_FORMAT_SHIFT_BITS,
146 )
147 }
148
149 #[inline]
151 pub fn target_format(&self) -> TextureFormat {
152 let code = ((self.bits() >> Self::COLOR_TARGET_FORMAT_SHIFT_BITS)
153 & Self::COLOR_TARGET_FORMAT_MASK_BITS) as u8;
154 texture_format_from_code(code)
155 .expect("Unknown bits in `COLOR_TARGET_FORMAT_MASK_BITS` of the pipeline key")
156 }
157
158 #[inline]
160 pub fn from_compositing_space(space: Option<CompositingSpace>) -> Self {
161 match space {
162 Some(CompositingSpace::Srgb) => Self::SRGB_COMPOSITING,
163 Some(CompositingSpace::Oklab) => Self::OKLAB_COMPOSITING,
164 Some(CompositingSpace::Linear) | None => Self::NONE,
165 }
166 }
167}
168
169impl SpecializedRenderPipeline for SpritePipeline {
170 type Key = SpritePipelineKey;
171
172 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
173 let mut shader_defs = Vec::new();
174 if key.contains(SpritePipelineKey::TONEMAP_IN_SHADER) {
175 shader_defs.push("TONEMAP_IN_SHADER".into());
176 shader_defs.push(ShaderDefVal::UInt(
177 "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
178 1,
179 ));
180 shader_defs.push(ShaderDefVal::UInt(
181 "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
182 2,
183 ));
184
185 let method = key.intersection(SpritePipelineKey::TONEMAP_METHOD_RESERVED_BITS);
186
187 if method == SpritePipelineKey::TONEMAP_METHOD_LINEAR {
188 shader_defs.push("TONEMAP_METHOD_LINEAR".into());
189 } else if method == SpritePipelineKey::TONEMAP_METHOD_REINHARD {
190 shader_defs.push("TONEMAP_METHOD_REINHARD".into());
191 } else if method == SpritePipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
192 shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
193 } else if method == SpritePipelineKey::TONEMAP_METHOD_ACES_FITTED {
194 shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
195 } else if method == SpritePipelineKey::TONEMAP_METHOD_AGX {
196 shader_defs.push("TONEMAP_METHOD_AGX".into());
197 } else if method == SpritePipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
198 {
199 shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
200 } else if method == SpritePipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
201 shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
202 } else if method == SpritePipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
203 shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
204 } else if method == SpritePipelineKey::TONEMAP_METHOD_PBR_NEUTRAL {
205 shader_defs.push("TONEMAP_METHOD_PBR_NEUTRAL".into());
206 }
207
208 if key.contains(SpritePipelineKey::DEBAND_DITHER) {
210 shader_defs.push("DEBAND_DITHER".into());
211 }
212 }
213
214 if key.contains(SpritePipelineKey::SRGB_COMPOSITING) {
215 shader_defs.push("SRGB_OUTPUT".into());
216 }
217 if key.contains(SpritePipelineKey::OKLAB_COMPOSITING) {
218 shader_defs.push("OKLAB_OUTPUT".into());
219 }
220
221 let format = key.target_format();
222
223 let instance_rate_vertex_buffer_layout = VertexBufferLayout {
224 array_stride: 80,
225 step_mode: VertexStepMode::Instance,
226 attributes: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[VertexAttribute {
format: VertexFormat::Float32x4,
offset: 0,
shader_location: 0,
},
VertexAttribute {
format: VertexFormat::Float32x4,
offset: 16,
shader_location: 1,
},
VertexAttribute {
format: VertexFormat::Float32x4,
offset: 32,
shader_location: 2,
},
VertexAttribute {
format: VertexFormat::Float32x4,
offset: 48,
shader_location: 3,
},
VertexAttribute {
format: VertexFormat::Float32x4,
offset: 64,
shader_location: 4,
}]))vec![
227 VertexAttribute {
229 format: VertexFormat::Float32x4,
230 offset: 0,
231 shader_location: 0,
232 },
233 VertexAttribute {
235 format: VertexFormat::Float32x4,
236 offset: 16,
237 shader_location: 1,
238 },
239 VertexAttribute {
241 format: VertexFormat::Float32x4,
242 offset: 32,
243 shader_location: 2,
244 },
245 VertexAttribute {
247 format: VertexFormat::Float32x4,
248 offset: 48,
249 shader_location: 3,
250 },
251 VertexAttribute {
253 format: VertexFormat::Float32x4,
254 offset: 64,
255 shader_location: 4,
256 },
257 ],
258 };
259
260 RenderPipelineDescriptor {
261 vertex: VertexState {
262 shader: self.shader.clone(),
263 shader_defs: shader_defs.clone(),
264 buffers: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[instance_rate_vertex_buffer_layout]))vec![instance_rate_vertex_buffer_layout],
265 ..default()
266 },
267 fragment: Some(FragmentState {
268 shader: self.shader.clone(),
269 shader_defs,
270 targets: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Some(ColorTargetState {
format,
blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::ALL,
})]))vec![Some(ColorTargetState {
271 format,
272 blend: Some(BlendState::ALPHA_BLENDING),
273 write_mask: ColorWrites::ALL,
274 })],
275 ..default()
276 }),
277 layout: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.view_layout.clone(), self.material_layout.clone()]))vec![self.view_layout.clone(), self.material_layout.clone()],
278 depth_stencil: Some(DepthStencilState {
282 format: CORE_2D_DEPTH_FORMAT,
283 depth_write_enabled: Some(false),
284 depth_compare: Some(CompareFunction::GreaterEqual),
285 stencil: StencilState {
286 front: StencilFaceState::IGNORE,
287 back: StencilFaceState::IGNORE,
288 read_mask: 0,
289 write_mask: 0,
290 },
291 bias: DepthBiasState {
292 constant: 0,
293 slope_scale: 0.0,
294 clamp: 0.0,
295 },
296 }),
297 multisample: MultisampleState {
298 count: key.msaa_samples(),
299 mask: !0,
300 alpha_to_coverage_enabled: false,
301 },
302 label: Some("sprite_pipeline".into()),
303 ..default()
304 }
305 }
306}
307
308pub struct ExtractedSlice {
309 pub offset: Vec2,
310 pub rect: Rect,
311 pub size: Vec2,
312}
313
314pub struct ExtractedSprite {
315 pub main_entity: Entity,
316 pub render_entity: Entity,
317 pub transform: GlobalTransform,
318 pub color: LinearRgba,
319 pub image_handle_id: AssetId<Image>,
323 pub flip_y: bool,
324 pub kind: ExtractedSpriteKind,
325}
326
327pub enum ExtractedSpriteKind {
328 Single { custom_size: Vec2 },
330 Slices { indices: Range<usize> },
333}
334
335#[derive(impl bevy_ecs::component::Component for ExtractedSprites where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<ExtractedSprites>()
{
id
} else {
required_components.components_registrator().register_component::<ExtractedSprites>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for ExtractedSprites where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]impl ::core::default::Default for ExtractedSprites {
#[inline]
fn default() -> Self {
ExtractedSprites { sprites: ::core::default::Default::default() }
}
}Default)]
336pub struct ExtractedSprites {
337 pub sprites: Vec<ExtractedSprite>,
338}
339
340#[derive(impl bevy_ecs::component::Component for ExtractedSlices where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<ExtractedSlices>()
{
id
} else {
required_components.components_registrator().register_component::<ExtractedSlices>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for ExtractedSlices where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]impl ::core::default::Default for ExtractedSlices {
#[inline]
fn default() -> Self {
ExtractedSlices { slices: ::core::default::Default::default() }
}
}Default)]
341pub struct ExtractedSlices {
342 pub slices: Vec<ExtractedSlice>,
343}
344
345#[derive(impl bevy_ecs::component::Component for SpriteAssetEvents where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<SpriteAssetEvents>()
{
id
} else {
required_components.components_registrator().register_component::<SpriteAssetEvents>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for SpriteAssetEvents where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]impl ::core::default::Default for SpriteAssetEvents {
#[inline]
fn default() -> Self {
SpriteAssetEvents { images: ::core::default::Default::default() }
}
}Default)]
346pub struct SpriteAssetEvents {
347 pub images: Vec<AssetEvent<Image>>,
348}
349
350pub fn extract_sprite_events(
351 mut events: ResMut<SpriteAssetEvents>,
352 mut image_events: Extract<MessageReader<AssetEvent<Image>>>,
353) {
354 let SpriteAssetEvents { ref mut images } = *events;
355 images.clear();
356
357 for event in image_events.read() {
358 images.push(*event);
359 }
360}
361
362#[repr(C)]
363#[derive(#[automatically_derived]impl ::core::marker::Copy for SpriteInstance { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for SpriteInstance {
}
#[automatically_derived]impl ::core::clone::Clone for SpriteInstance {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<[Vec4; 3]>;
let _: ::core::clone::AssertParamIsClone<[f32; 4]>;
let _: ::core::clone::AssertParamIsClone<[f32; 4]>;
*self
}
}Clone, const _: () =
{
if !(::core::mem::size_of::<SpriteInstance>() ==
(::core::mem::size_of::<[Vec4; 3]>() +
::core::mem::size_of::<[f32; 4]>() +
::core::mem::size_of::<[f32; 4]>())) {
{
::std::rt::begin_panic("derive(Pod) was applied to a type with padding");
}
};
};
const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Pod>() {}
assert_impl::<[Vec4; 3]>();
}
};
const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Pod>() {}
assert_impl::<[f32; 4]>();
}
};
const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Pod>() {}
assert_impl::<[f32; 4]>();
}
};
unsafe impl ::bytemuck::Pod for SpriteInstance {}Pod, const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Zeroable>() {}
assert_impl::<[Vec4; 3]>();
}
};
const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Zeroable>() {}
assert_impl::<[f32; 4]>();
}
};
const _: fn() =
||
{
#[allow(clippy :: missing_const_for_fn)]
#[doc(hidden)]
fn check() {
fn assert_impl<T: ::bytemuck::Zeroable>() {}
assert_impl::<[f32; 4]>();
}
};
unsafe impl ::bytemuck::Zeroable for SpriteInstance {}Zeroable)]
364struct SpriteInstance {
365 pub i_model_transpose: [Vec4; 3],
367 pub i_color: [f32; 4],
368 pub i_uv_offset_scale: [f32; 4],
369}
370
371impl SpriteInstance {
372 #[inline]
373 fn from(transform: &Affine3A, color: &LinearRgba, uv_offset_scale: &Vec4) -> Self {
374 let transpose_model_3x3 = transform.matrix3.transpose();
375 Self {
376 i_model_transpose: [
377 transpose_model_3x3.x_axis.extend(transform.translation.x),
378 transpose_model_3x3.y_axis.extend(transform.translation.y),
379 transpose_model_3x3.z_axis.extend(transform.translation.z),
380 ],
381 i_color: color.to_f32_array(),
382 i_uv_offset_scale: uv_offset_scale.to_array(),
383 }
384 }
385}
386
387#[derive(impl bevy_ecs::component::Component for SpriteMeta where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<SpriteMeta>()
{
id
} else {
required_components.components_registrator().register_component::<SpriteMeta>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for SpriteMeta where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource)]
388pub struct SpriteMeta {
389 sprite_index_buffer: RawBufferVec<u32>,
390 sprite_instance_buffer: RawBufferVec<SpriteInstance>,
391}
392
393impl Default for SpriteMeta {
394 fn default() -> Self {
395 Self {
396 sprite_index_buffer: RawBufferVec::<u32>::new(BufferUsages::INDEX),
397 sprite_instance_buffer: RawBufferVec::<SpriteInstance>::new(BufferUsages::VERTEX),
398 }
399 }
400}
401
402#[derive(impl bevy_ecs::component::Component for SpriteViewBindGroup where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}Component)]
403pub struct SpriteViewBindGroup {
404 pub value: BindGroup,
405}
406
407#[derive(impl bevy_ecs::component::Component for SpriteBatches where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<SpriteBatches>()
{
id
} else {
required_components.components_registrator().register_component::<SpriteBatches>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for SpriteBatches where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, impl ::core::ops::Deref for SpriteBatches {
type Target = HashMap<(RetainedViewEntity, Entity), SpriteBatch>;
fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for SpriteBatches {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut, #[automatically_derived]impl ::core::default::Default for SpriteBatches {
#[inline]
fn default() -> Self {
SpriteBatches(::core::default::Default::default())
}
}Default)]
408pub struct SpriteBatches(HashMap<(RetainedViewEntity, Entity), SpriteBatch>);
409
410#[derive(#[automatically_derived]impl ::core::marker::StructuralPartialEq for
SpriteBatch {
}
#[automatically_derived]impl ::core::cmp::PartialEq for SpriteBatch {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.image_handle_id == other.image_handle_id &&
self.range == other.range
}
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for SpriteBatch {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<AssetId<Image>>;
let _: ::core::cmp::AssertParamIsEq<Range<u32>>;
}
}Eq, #[automatically_derived]impl ::core::clone::Clone for SpriteBatch {
#[inline]
fn clone(&self) -> Self {
SpriteBatch {
image_handle_id: ::core::clone::Clone::clone(&self.image_handle_id),
range: ::core::clone::Clone::clone(&self.range),
}
}
}Clone, #[automatically_derived]impl ::core::fmt::Debug for SpriteBatch {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SpriteBatch",
"image_handle_id", &self.image_handle_id, "range", &&self.range)
}
}Debug)]
411pub struct SpriteBatch {
412 image_handle_id: AssetId<Image>,
413 range: Range<u32>,
414}
415
416#[derive(impl bevy_ecs::component::Component for ImageBindGroups where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<ImageBindGroups>()
{
id
} else {
required_components.components_registrator().register_component::<ImageBindGroups>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for ImageBindGroups where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]impl ::core::default::Default for ImageBindGroups {
#[inline]
fn default() -> Self {
ImageBindGroups { values: ::core::default::Default::default() }
}
}Default)]
417pub struct ImageBindGroups {
418 values: HashMap<AssetId<Image>, BindGroup>,
419}
420
421pub fn queue_sprites(
422 mut view_entities: Local<FixedBitSet>,
423 draw_functions: Res<DrawFunctions<Transparent2d>>,
424 sprite_pipeline: Res<SpritePipeline>,
425 mut pipelines: ResMut<SpecializedRenderPipelines<SpritePipeline>>,
426 pipeline_cache: Res<PipelineCache>,
427 extracted_sprites: Res<ExtractedSprites>,
428 mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
429 mut cameras: Query<(
430 &RenderVisibleEntities,
431 &ExtractedCamera,
432 &ExtractedView,
433 &Msaa,
434 Option<&Tonemapping>,
435 Option<&DebandDither>,
436 Option<&ResolvedCompositingSpace>,
437 )>,
438) {
439 let draw_sprite_function = draw_functions.read().id::<DrawSprite>();
440
441 for (visible_entities, camera, view, msaa, tonemapping, dither, resolved_space) in &mut cameras
442 {
443 let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity)
444 else {
445 continue;
446 };
447
448 let mut view_key = SpritePipelineKey::from_target_format(view.target_format)
449 | SpritePipelineKey::from_msaa_samples(msaa.samples())
450 | SpritePipelineKey::from_compositing_space(ResolvedCompositingSpace::space(
451 resolved_space,
452 ));
453
454 if !camera.hdr
455 && let Some(tonemapping) = tonemapping
456 && tonemapping.is_enabled()
457 {
458 view_key |= SpritePipelineKey::TONEMAP_IN_SHADER;
459 view_key |= match tonemapping {
460 Tonemapping::None | Tonemapping::Linear => SpritePipelineKey::TONEMAP_METHOD_LINEAR,
461 Tonemapping::Reinhard => SpritePipelineKey::TONEMAP_METHOD_REINHARD,
462 Tonemapping::ReinhardLuminance => {
463 SpritePipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE
464 }
465 Tonemapping::AcesFitted => SpritePipelineKey::TONEMAP_METHOD_ACES_FITTED,
466 Tonemapping::AgX => SpritePipelineKey::TONEMAP_METHOD_AGX,
467 Tonemapping::SomewhatBoringDisplayTransform => {
468 SpritePipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
469 }
470 Tonemapping::TonyMcMapface => SpritePipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE,
471 Tonemapping::BlenderFilmic => SpritePipelineKey::TONEMAP_METHOD_BLENDER_FILMIC,
472 Tonemapping::KhronosPbrNeutral => SpritePipelineKey::TONEMAP_METHOD_PBR_NEUTRAL,
473 };
474 if let Some(DebandDither::Enabled) = dither {
475 view_key |= SpritePipelineKey::DEBAND_DITHER;
476 }
477 }
478
479 let pipeline = pipelines.specialize(&pipeline_cache, &sprite_pipeline, view_key);
480
481 view_entities.clear();
482 if let Some(visible_entities) = visible_entities.get::<Sprite>() {
483 view_entities.extend(
484 visible_entities
485 .iter_visible()
486 .map(|(_, e)| e.index_u32() as usize),
487 );
488 }
489
490 transparent_phase
491 .items
492 .reserve(extracted_sprites.sprites.len());
493
494 for (index, extracted_sprite) in extracted_sprites.sprites.iter().enumerate() {
495 let view_index = extracted_sprite.main_entity.index_u32();
496
497 if !view_entities.contains(view_index as usize) {
498 continue;
499 }
500
501 let sort_key = FloatOrd(extracted_sprite.transform.translation().z);
503
504 transparent_phase.add_transient(Transparent2d {
506 draw_function: draw_sprite_function,
507 pipeline,
508 entity: (
509 extracted_sprite.render_entity,
510 extracted_sprite.main_entity.into(),
511 ),
512 sort_key,
513 batch_range: 0..0,
515 extra_index: PhaseItemExtraIndex::None,
516 extracted_index: index,
517 indexed: true,
518 });
519 }
520 }
521}
522
523pub fn prepare_sprite_view_bind_groups(
524 mut commands: Commands,
525 render_device: Res<RenderDevice>,
526 pipeline_cache: Res<PipelineCache>,
527 sprite_pipeline: Res<SpritePipeline>,
528 view_uniforms: Res<ViewUniforms>,
529 views: Query<(Entity, &Tonemapping), With<ExtractedView>>,
530 tonemapping_luts: Res<TonemappingLuts>,
531 images: Res<RenderAssets<GpuImage>>,
532 fallback_image: Res<FallbackImage>,
533) {
534 let Some(view_binding) = view_uniforms.uniforms.binding() else {
535 return;
536 };
537
538 for (entity, tonemapping) in &views {
539 let lut_bindings =
540 get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);
541 let view_bind_group = render_device.create_bind_group(
542 "mesh2d_view_bind_group",
543 &pipeline_cache.get_bind_group_layout(&sprite_pipeline.view_layout),
544 &BindGroupEntries::sequential((view_binding.clone(), lut_bindings.0, lut_bindings.1)),
545 );
546
547 commands.entity(entity).insert(SpriteViewBindGroup {
548 value: view_bind_group,
549 });
550 }
551}
552
553pub fn prepare_sprite_image_bind_groups(
554 render_device: Res<RenderDevice>,
555 render_queue: Res<RenderQueue>,
556 pipeline_cache: Res<PipelineCache>,
557 mut sprite_meta: ResMut<SpriteMeta>,
558 sprite_pipeline: Res<SpritePipeline>,
559 mut image_bind_groups: ResMut<ImageBindGroups>,
560 gpu_images: Res<RenderAssets<GpuImage>>,
561 extracted_sprites: Res<ExtractedSprites>,
562 extracted_slices: Res<ExtractedSlices>,
563 mut phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
564 events: Res<SpriteAssetEvents>,
565 mut batches: ResMut<SpriteBatches>,
566) {
567 for event in &events.images {
569 match event {
570 AssetEvent::Added { .. } |
571 AssetEvent::LoadedWithDependencies { .. } => {}
573 AssetEvent::Unused { id } | AssetEvent::Modified { id } | AssetEvent::Removed { id } => {
574 image_bind_groups.values.remove(id);
575 }
576 };
577 }
578
579 batches.clear();
580
581 sprite_meta.sprite_instance_buffer.clear();
583
584 let mut index = 0;
586
587 let image_bind_groups = &mut *image_bind_groups;
588
589 for (retained_view, transparent_phase) in phases.iter_mut() {
590 let mut current_batch = None;
591 let mut batch_item_index = 0;
592 let mut batch_image_size = Vec2::ZERO;
593 let mut batch_image_handle = None;
594
595 for item_index in 0..transparent_phase.items.len() {
599 let item = &transparent_phase.items[item_index];
600
601 let Some(extracted_sprite) = extracted_sprites
602 .sprites
603 .get(item.extracted_index)
604 .filter(|extracted_sprite| extracted_sprite.render_entity == item.entity())
605 else {
606 batch_image_handle = None;
610 continue;
611 };
612
613 if batch_image_handle != Some(extracted_sprite.image_handle_id) {
614 let Some(gpu_image) = gpu_images.get(extracted_sprite.image_handle_id) else {
615 continue;
616 };
617
618 batch_image_size = gpu_image.size_2d().as_vec2();
619 let image_handle = extracted_sprite.image_handle_id;
620 batch_image_handle = Some(image_handle);
621 image_bind_groups
622 .values
623 .entry(image_handle)
624 .or_insert_with(|| {
625 render_device.create_bind_group(
626 "sprite_material_bind_group",
627 &pipeline_cache.get_bind_group_layout(&sprite_pipeline.material_layout),
628 &BindGroupEntries::sequential((
629 &gpu_image.texture_view,
630 &gpu_image.sampler,
631 )),
632 )
633 });
634
635 batch_item_index = item_index;
636 current_batch = Some(batches.entry((*retained_view, item.entity())).insert(
637 SpriteBatch {
638 image_handle_id: image_handle,
639 range: index..index,
640 },
641 ));
642 }
643 match extracted_sprite.kind {
644 ExtractedSpriteKind::Single { custom_size } => {
645 let mut uv_offset_scale = Vec4::new(0.0, 1.0, 1.0, -1.0);
646
647 if extracted_sprite.flip_y {
648 uv_offset_scale.y += uv_offset_scale.w;
649 uv_offset_scale.w *= -1.0;
650 }
651
652 let transform = extracted_sprite.transform.affine()
653 * Affine3A::from_scale_rotation_translation(
654 custom_size.extend(1.0),
655 Quat::IDENTITY,
656 (custom_size * -Vec2::splat(0.5)).extend(0.0),
657 );
658
659 sprite_meta
661 .sprite_instance_buffer
662 .push(SpriteInstance::from(
663 &transform,
664 &extracted_sprite.color,
665 &uv_offset_scale,
666 ));
667
668 current_batch.as_mut().unwrap().get_mut().range.end += 1;
669 index += 1;
670 }
671 ExtractedSpriteKind::Slices { ref indices } => {
672 for i in indices.clone() {
673 let slice = &extracted_slices.slices[i];
674 let rect = slice.rect;
675 let rect_size = rect.size();
676
677 let mut uv_offset_scale: Vec4;
679
680 uv_offset_scale = Vec4::new(
682 rect.min.x / batch_image_size.x,
683 rect.max.y / batch_image_size.y,
684 rect_size.x / batch_image_size.x,
685 -rect_size.y / batch_image_size.y,
686 );
687
688 if extracted_sprite.flip_y {
689 uv_offset_scale.y += uv_offset_scale.w;
690 uv_offset_scale.w *= -1.0;
691 }
692
693 let transform = extracted_sprite.transform.affine()
694 * Affine3A::from_scale_rotation_translation(
695 slice.size.extend(1.0),
696 Quat::IDENTITY,
697 (slice.size * -Vec2::splat(0.5) + slice.offset).extend(0.0),
698 );
699
700 sprite_meta
702 .sprite_instance_buffer
703 .push(SpriteInstance::from(
704 &transform,
705 &extracted_sprite.color,
706 &uv_offset_scale,
707 ));
708
709 current_batch.as_mut().unwrap().get_mut().range.end += 1;
710 index += 1;
711 }
712 }
713 }
714 transparent_phase.items[batch_item_index]
715 .batch_range_mut()
716 .end += 1;
717 }
718 sprite_meta
719 .sprite_instance_buffer
720 .write_buffer(&render_device, &render_queue);
721
722 if sprite_meta.sprite_index_buffer.len() != 6 {
723 sprite_meta.sprite_index_buffer.clear();
724
725 sprite_meta.sprite_index_buffer.push(2);
735 sprite_meta.sprite_index_buffer.push(0);
736 sprite_meta.sprite_index_buffer.push(1);
737 sprite_meta.sprite_index_buffer.push(1);
738 sprite_meta.sprite_index_buffer.push(3);
739 sprite_meta.sprite_index_buffer.push(2);
740
741 sprite_meta
742 .sprite_index_buffer
743 .write_buffer(&render_device, &render_queue);
744 }
745 }
746}
747pub type DrawSprite = (
749 SetItemPipeline,
750 SetSpriteViewBindGroup<0>,
751 SetSpriteTextureBindGroup<1>,
752 DrawSpriteBatch,
753);
754
755pub struct SetSpriteViewBindGroup<const I: usize>;
756impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteViewBindGroup<I> {
757 type Param = ();
758 type ViewQuery = (Read<ViewUniformOffset>, Read<SpriteViewBindGroup>);
759 type ItemQuery = ();
760
761 fn render<'w>(
762 _item: &P,
763 (view_uniform, sprite_view_bind_group): ROQueryItem<'w, '_, Self::ViewQuery>,
764 _entity: Option<()>,
765 _param: SystemParamItem<'w, '_, Self::Param>,
766 pass: &mut TrackedRenderPass<'w>,
767 ) -> RenderCommandResult {
768 pass.set_bind_group(I, &sprite_view_bind_group.value, &[view_uniform.offset]);
769 RenderCommandResult::Success
770 }
771}
772pub struct SetSpriteTextureBindGroup<const I: usize>;
773impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetSpriteTextureBindGroup<I> {
774 type Param = (SRes<ImageBindGroups>, SRes<SpriteBatches>);
775 type ViewQuery = Read<ExtractedView>;
776 type ItemQuery = ();
777
778 fn render<'w>(
779 item: &P,
780 view: ROQueryItem<'w, '_, Self::ViewQuery>,
781 _entity: Option<()>,
782 (image_bind_groups, batches): SystemParamItem<'w, '_, Self::Param>,
783 pass: &mut TrackedRenderPass<'w>,
784 ) -> RenderCommandResult {
785 let image_bind_groups = image_bind_groups.into_inner();
786 let Some(batch) = batches.get(&(view.retained_view_entity, item.entity())) else {
787 return RenderCommandResult::Skip;
788 };
789
790 pass.set_bind_group(
791 I,
792 image_bind_groups
793 .values
794 .get(&batch.image_handle_id)
795 .unwrap(),
796 &[],
797 );
798 RenderCommandResult::Success
799 }
800}
801
802pub struct DrawSpriteBatch;
803impl<P: PhaseItem> RenderCommand<P> for DrawSpriteBatch {
804 type Param = (SRes<SpriteMeta>, SRes<SpriteBatches>);
805 type ViewQuery = Read<ExtractedView>;
806 type ItemQuery = ();
807
808 fn render<'w>(
809 item: &P,
810 view: ROQueryItem<'w, '_, Self::ViewQuery>,
811 _entity: Option<()>,
812 (sprite_meta, batches): SystemParamItem<'w, '_, Self::Param>,
813 pass: &mut TrackedRenderPass<'w>,
814 ) -> RenderCommandResult {
815 let sprite_meta = sprite_meta.into_inner();
816 let Some(batch) = batches.get(&(view.retained_view_entity, item.entity())) else {
817 return RenderCommandResult::Skip;
818 };
819
820 pass.set_index_buffer(
821 sprite_meta.sprite_index_buffer.buffer().unwrap().slice(..),
822 IndexFormat::Uint32,
823 );
824 pass.set_vertex_buffer(
825 0,
826 sprite_meta
827 .sprite_instance_buffer
828 .buffer()
829 .unwrap()
830 .slice(..),
831 );
832 pass.draw_indexed(0..6, 0, batch.range.clone());
833 RenderCommandResult::Success
834 }
835}