Skip to main content

bevy_render/render_phase/
draw.rs

1use bevy_material::labels::DrawFunctionId;
2
3use crate::render_phase::{PhaseItem, TrackedRenderPass};
4use bevy_app::{App, SubApp};
5use bevy_ecs::{
6    entity::Entity,
7    query::{QueryEntityError, QueryState, ROQueryItem, ReadOnlyQueryData},
8    resource::Resource,
9    system::{ReadOnlySystemParam, SystemParam, SystemParamItem, SystemState},
10    world::World,
11};
12use bevy_utils::TypeIdHashMap;
13use core::{any::TypeId, fmt::Debug};
14use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
15use thiserror::Error;
16use variadics_please::all_tuples;
17
18/// A draw function used to draw [`PhaseItem`]s.
19///
20/// The draw function can retrieve and query the required ECS data from the render world.
21///
22/// This trait can either be implemented directly or implicitly composed out of multiple modular
23/// [`RenderCommand`]s. For more details and an example see the [`RenderCommand`] documentation.
24pub trait Draw<P: PhaseItem>: Send + Sync + 'static {
25    /// Prepares the draw function to be used. This is called once and only once before the phase
26    /// begins. There may be zero or more [`draw`](Draw::draw) calls following a call to this function.
27    /// Implementing this is optional.
28    #[expect(
29        unused_variables,
30        reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
31    )]
32    fn prepare(&mut self, world: &'_ World) {}
33
34    /// Draws a [`PhaseItem`] by issuing zero or more `draw` calls via the [`TrackedRenderPass`].
35    fn draw<'w>(
36        &mut self,
37        world: &'w World,
38        pass: &mut TrackedRenderPass<'w>,
39        view: Entity,
40        item: &P,
41    ) -> Result<(), DrawError>;
42}
43
44#[derive(#[allow(unused_qualifications)]
#[automatically_derived]
impl ::thiserror::__private21::Error for DrawError { }
#[allow(unused_qualifications)]
#[automatically_derived]
impl ::core::fmt::Display for DrawError {
    fn fmt(&self, __formatter: &mut ::core::fmt::Formatter)
        -> ::core::fmt::Result {

        #[allow(unused_variables, deprecated, clippy ::
        used_underscore_binding)]
        match self {
            DrawError::RenderCommandFailure(_0) =>
                match (_0,) {
                    (__field0,) =>
                        __formatter.write_fmt(format_args!("Failed to execute render command {0:?}",
                                __field0)),
                },
            DrawError::InvalidViewQuery {} =>
                __formatter.write_str("Failed to get execute view query"),
            DrawError::ViewEntityNotFound {} =>
                __formatter.write_str("View entity not found"),
        }
    }
}Error, #[automatically_derived]impl ::core::fmt::Debug for DrawError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::RenderCommandFailure(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "RenderCommandFailure", &__self_0),
            Self::InvalidViewQuery =>
                ::core::fmt::Formatter::write_str(f, "InvalidViewQuery"),
            Self::ViewEntityNotFound =>
                ::core::fmt::Formatter::write_str(f, "ViewEntityNotFound"),
        }
    }
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for DrawError
    {
}
#[automatically_derived]impl ::core::cmp::PartialEq for DrawError {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::RenderCommandFailure(__self_0),
                    Self::RenderCommandFailure(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for DrawError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<&'static str>;
    }
}Eq)]
45pub enum DrawError {
46    #[error("Failed to execute render command {0:?}")]
47    RenderCommandFailure(&'static str),
48    #[error("Failed to get execute view query")]
49    InvalidViewQuery,
50    #[error("View entity not found")]
51    ViewEntityNotFound,
52}
53
54/// Stores all [`Draw`] functions for the [`PhaseItem`] type.
55///
56/// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s.
57pub struct DrawFunctionsInternal<P: PhaseItem> {
58    pub draw_functions: Vec<Box<dyn Draw<P>>>,
59    pub indices: TypeIdHashMap<DrawFunctionId>,
60}
61
62impl<P: PhaseItem> DrawFunctionsInternal<P> {
63    /// Prepares all draw function. This is called once and only once before the phase begins.
64    pub fn prepare(&mut self, world: &World) {
65        for function in &mut self.draw_functions {
66            function.prepare(world);
67        }
68    }
69
70    /// Adds the [`Draw`] function and maps it to its own type.
71    pub fn add<T: Draw<P>>(&mut self, draw_function: T) -> DrawFunctionId {
72        self.add_with::<T, T>(draw_function)
73    }
74
75    /// Adds the [`Draw`] function and maps it to the type `T`
76    pub fn add_with<T: 'static, D: Draw<P>>(&mut self, draw_function: D) -> DrawFunctionId {
77        let id = DrawFunctionId(self.draw_functions.len().try_into().unwrap());
78        self.draw_functions.push(Box::new(draw_function));
79        self.indices.insert(TypeId::of::<T>(), id);
80        id
81    }
82
83    /// Retrieves the [`Draw`] function corresponding to the `id` mutably.
84    pub fn get_mut(&mut self, id: DrawFunctionId) -> Option<&mut dyn Draw<P>> {
85        self.draw_functions.get_mut(id.0 as usize).map(|f| &mut **f)
86    }
87
88    /// Retrieves the id of the [`Draw`] function corresponding to their associated type `T`.
89    pub fn get_id<T: 'static>(&self) -> Option<DrawFunctionId> {
90        self.indices.get(&TypeId::of::<T>()).copied()
91    }
92
93    /// Retrieves the id of the [`Draw`] function corresponding to their associated type `T`.
94    ///
95    /// Fallible wrapper for [`Self::get_id()`]
96    ///
97    /// ## Panics
98    /// If the id doesn't exist, this function will panic.
99    pub fn id<T: 'static>(&self) -> DrawFunctionId {
100        self.get_id::<T>().unwrap_or_else(|| {
101            {
    ::core::panicking::panic_fmt(format_args!("Draw function {0} not found for {1}",
            core::any::type_name::<T>(), core::any::type_name::<P>()));
}panic!(
102                "Draw function {} not found for {}",
103                core::any::type_name::<T>(),
104                core::any::type_name::<P>()
105            )
106        })
107    }
108}
109
110/// Stores all draw functions for the [`PhaseItem`] type hidden behind a reader-writer lock.
111///
112/// To access them the [`DrawFunctions::read`] and [`DrawFunctions::write`] methods are used.
113#[derive(impl<P: PhaseItem> bevy_ecs::component::Component for DrawFunctions<P> 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::<DrawFunctions<P>>()
                {
                id
            } else {
                required_components.components_registrator().register_component::<DrawFunctions<P>>()
            };
        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<P: PhaseItem> bevy_ecs::resource::Resource for DrawFunctions<P> where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource)]
114pub struct DrawFunctions<P: PhaseItem> {
115    internal: RwLock<DrawFunctionsInternal<P>>,
116}
117
118impl<P: PhaseItem> Default for DrawFunctions<P> {
119    fn default() -> Self {
120        Self {
121            internal: RwLock::new(DrawFunctionsInternal {
122                draw_functions: Vec::new(),
123                indices: Default::default(),
124            }),
125        }
126    }
127}
128
129impl<P: PhaseItem> DrawFunctions<P> {
130    /// Accesses the draw functions in read mode.
131    pub fn read(&self) -> RwLockReadGuard<'_, DrawFunctionsInternal<P>> {
132        self.internal.read().unwrap_or_else(PoisonError::into_inner)
133    }
134
135    /// Accesses the draw functions in write mode.
136    pub fn write(&self) -> RwLockWriteGuard<'_, DrawFunctionsInternal<P>> {
137        self.internal
138            .write()
139            .unwrap_or_else(PoisonError::into_inner)
140    }
141}
142
143/// [`RenderCommand`]s are modular standardized pieces of render logic that can be composed into
144/// [`Draw`] functions.
145///
146/// To turn a stateless render command into a usable draw function it has to be wrapped by a
147/// [`RenderCommandState`].
148/// This is done automatically when registering a render command as a [`Draw`] function via the
149/// [`AddRenderCommand::add_render_command`] method.
150///
151/// Compared to the draw function the required ECS data is fetched automatically
152/// (by the [`RenderCommandState`]) from the render world.
153/// Therefore the three types [`Param`](RenderCommand::Param),
154/// [`ViewQuery`](RenderCommand::ViewQuery) and
155/// [`ItemQuery`](RenderCommand::ItemQuery) are used.
156/// They specify which information is required to execute the render command.
157///
158/// Multiple render commands can be combined together by wrapping them in a tuple.
159///
160/// # Example
161///
162/// The `DrawMaterial` draw function is created from the following render command
163/// tuple. Const generics are used to set specific bind group locations:
164///
165/// ```
166/// # use bevy_render::render_phase::SetItemPipeline;
167/// # struct SetMeshViewBindGroup<const N: usize>;
168/// # struct SetMeshViewBindingArrayBindGroup<const N: usize>;
169/// # struct SetMeshBindGroup<const N: usize>;
170/// # struct SetMaterialBindGroup<M, const N: usize>(std::marker::PhantomData<M>);
171/// # struct DrawMesh;
172/// pub type DrawMaterial<M> = (
173///     SetItemPipeline,
174///     SetMeshViewBindGroup<0>,
175///     SetMeshViewBindingArrayBindGroup<1>,
176///     SetMeshBindGroup<2>,
177///     SetMaterialBindGroup<M, 3>,
178///     DrawMesh,
179/// );
180/// ```
181pub trait RenderCommand<P: PhaseItem> {
182    /// Specifies the general ECS data (e.g. resources) required by [`RenderCommand::render`].
183    ///
184    /// When fetching resources, note that, due to lifetime limitations of the `Deref` trait,
185    /// [`SRes::into_inner`] must be called on each [`SRes`] reference in the
186    /// [`RenderCommand::render`] method, instead of being automatically dereferenced as is the
187    /// case in normal `systems`.
188    ///
189    /// All parameters have to be read only.
190    ///
191    /// [`SRes`]: bevy_ecs::system::lifetimeless::SRes
192    /// [`SRes::into_inner`]: bevy_ecs::system::lifetimeless::SRes::into_inner
193    type Param: SystemParam + 'static;
194    /// Specifies the ECS data of the view entity required by [`RenderCommand::render`].
195    ///
196    /// The view entity refers to the camera, or shadow-casting light, etc. from which the phase
197    /// item will be rendered from.
198    /// All components have to be accessed read only.
199    type ViewQuery: ReadOnlyQueryData;
200    /// Specifies the ECS data of the item entity required by [`RenderCommand::render`].
201    ///
202    /// The item is the entity that will be rendered for the corresponding view.
203    /// All components have to be accessed read only.
204    ///
205    /// For efficiency reasons, Bevy doesn't always extract entities to the
206    /// render world; for instance, entities that simply consist of meshes are
207    /// often not extracted. If the entity doesn't exist in the render world,
208    /// the supplied query data will be `None`.
209    type ItemQuery: ReadOnlyQueryData;
210
211    /// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups,
212    /// issuing draw calls, etc.) via the [`TrackedRenderPass`].
213    fn render<'w>(
214        item: &P,
215        view: ROQueryItem<'w, '_, Self::ViewQuery>,
216        entity: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
217        param: SystemParamItem<'w, '_, Self::Param>,
218        pass: &mut TrackedRenderPass<'w>,
219    ) -> RenderCommandResult;
220}
221
222/// The result of a [`RenderCommand`].
223#[derive(#[automatically_derived]impl ::core::fmt::Debug for RenderCommandResult {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Success => ::core::fmt::Formatter::write_str(f, "Success"),
            Self::Skip => ::core::fmt::Formatter::write_str(f, "Skip"),
            Self::Failure(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Failure", &__self_0),
        }
    }
}Debug)]
224pub enum RenderCommandResult {
225    Success,
226    Skip,
227    Failure(&'static str),
228}
229
230macro_rules! render_command_tuple_impl {
231    ($(#[$meta:meta])* $(($name: ident, $view: ident, $entity: ident)),*) => {
232        $(#[$meta])*
233        impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
234            type Param = ($($name::Param,)*);
235            type ViewQuery = ($($name::ViewQuery,)*);
236            type ItemQuery = ($($name::ItemQuery,)*);
237
238            #[expect(
239                clippy::allow_attributes,
240                reason = "We are in a macro; as such, `non_snake_case` may not always lint."
241            )]
242            #[allow(
243                non_snake_case,
244                reason = "Parameter and variable names are provided by the macro invocation, not by us."
245            )]
246            fn render<'w>(
247                _item: &P,
248                ($($view,)*): ROQueryItem<'w, '_, Self::ViewQuery>,
249                maybe_entities: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
250                ($($name,)*): SystemParamItem<'w, '_, Self::Param>,
251                _pass: &mut TrackedRenderPass<'w>,
252            ) -> RenderCommandResult {
253                match maybe_entities {
254                    None => {
255                        $(
256                            match $name::render(_item, $view, None, $name, _pass) {
257                                RenderCommandResult::Skip => return RenderCommandResult::Skip,
258                                RenderCommandResult::Failure(reason) => return RenderCommandResult::Failure(reason),
259                                _ => {},
260                            }
261                        )*
262                    }
263                    Some(($($entity,)*)) => {
264                        $(
265                            match $name::render(_item, $view, Some($entity), $name, _pass) {
266                                RenderCommandResult::Skip => return RenderCommandResult::Skip,
267                                RenderCommandResult::Failure(reason) => return RenderCommandResult::Failure(reason),
268                                _ => {},
269                            }
270                        )*
271                    }
272                }
273                RenderCommandResult::Success
274            }
275        }
276    };
277}
278
279#[doc(hidden)]
impl<P: PhaseItem, C0: RenderCommand<P>, C1: RenderCommand<P>,
    C2: RenderCommand<P>, C3: RenderCommand<P>, C4: RenderCommand<P>,
    C5: RenderCommand<P>, C6: RenderCommand<P>, C7: RenderCommand<P>,
    C8: RenderCommand<P>, C9: RenderCommand<P>, C10: RenderCommand<P>,
    C11: RenderCommand<P>, C12: RenderCommand<P>, C13: RenderCommand<P>,
    C14: RenderCommand<P>> RenderCommand<P> for
    (C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14) {
    type Param =
        (C0::Param, C1::Param, C2::Param, C3::Param, C4::Param, C5::Param,
        C6::Param, C7::Param, C8::Param, C9::Param, C10::Param, C11::Param,
        C12::Param, C13::Param, C14::Param);
    type ViewQuery =
        (C0::ViewQuery, C1::ViewQuery, C2::ViewQuery, C3::ViewQuery,
        C4::ViewQuery, C5::ViewQuery, C6::ViewQuery, C7::ViewQuery,
        C8::ViewQuery, C9::ViewQuery, C10::ViewQuery, C11::ViewQuery,
        C12::ViewQuery, C13::ViewQuery, C14::ViewQuery);
    type ItemQuery =
        (C0::ItemQuery, C1::ItemQuery, C2::ItemQuery, C3::ItemQuery,
        C4::ItemQuery, C5::ItemQuery, C6::ItemQuery, C7::ItemQuery,
        C8::ItemQuery, C9::ItemQuery, C10::ItemQuery, C11::ItemQuery,
        C12::ItemQuery, C13::ItemQuery, C14::ItemQuery);
    #[expect(clippy :: allow_attributes, reason =
    "We are in a macro; as such, `non_snake_case` may not always lint.")]
    #[allow(non_snake_case, reason =
    "Parameter and variable names are provided by the macro invocation, not by us.")]
    fn render<'w>(_item: &P,
        (V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14):
            ROQueryItem<'w, '_, Self::ViewQuery>,
        maybe_entities: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
        (C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14):
            SystemParamItem<'w, '_, Self::Param>,
        _pass: &mut TrackedRenderPass<'w>) -> RenderCommandResult {
        match maybe_entities {
            None => {
                match C0::render(_item, V0, None, C0, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C1::render(_item, V1, None, C1, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C2::render(_item, V2, None, C2, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C3::render(_item, V3, None, C3, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C4::render(_item, V4, None, C4, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C5::render(_item, V5, None, C5, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C6::render(_item, V6, None, C6, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C7::render(_item, V7, None, C7, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C8::render(_item, V8, None, C8, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C9::render(_item, V9, None, C9, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C10::render(_item, V10, None, C10, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C11::render(_item, V11, None, C11, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C12::render(_item, V12, None, C12, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C13::render(_item, V13, None, C13, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C14::render(_item, V14, None, C14, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
            }
            Some((E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13,
                E14)) => {
                match C0::render(_item, V0, Some(E0), C0, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C1::render(_item, V1, Some(E1), C1, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C2::render(_item, V2, Some(E2), C2, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C3::render(_item, V3, Some(E3), C3, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C4::render(_item, V4, Some(E4), C4, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C5::render(_item, V5, Some(E5), C5, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C6::render(_item, V6, Some(E6), C6, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C7::render(_item, V7, Some(E7), C7, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C8::render(_item, V8, Some(E8), C8, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C9::render(_item, V9, Some(E9), C9, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C10::render(_item, V10, Some(E10), C10, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C11::render(_item, V11, Some(E11), C11, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C12::render(_item, V12, Some(E12), C12, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C13::render(_item, V13, Some(E13), C13, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
                match C14::render(_item, V14, Some(E14), C14, _pass) {
                    RenderCommandResult::Skip =>
                        return RenderCommandResult::Skip,
                    RenderCommandResult::Failure(reason) =>
                        return RenderCommandResult::Failure(reason),
                    _ => {}
                }
            }
        }
        RenderCommandResult::Success
    }
}all_tuples!(
280    #[doc(fake_variadic)]
281    render_command_tuple_impl,
282    0,
283    15,
284    C,
285    V,
286    E
287);
288
289/// Wraps a [`RenderCommand`] into a state so that it can be used as a [`Draw`] function.
290///
291/// The [`RenderCommand::Param`], [`RenderCommand::ViewQuery`] and
292/// [`RenderCommand::ItemQuery`] are fetched from the ECS and passed to the command.
293pub struct RenderCommandState<P: PhaseItem + 'static, C: RenderCommand<P>> {
294    state: SystemState<C::Param>,
295    view: QueryState<C::ViewQuery>,
296    entity: QueryState<C::ItemQuery>,
297}
298
299impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> {
300    /// Creates a new [`RenderCommandState`] for the [`RenderCommand`].
301    pub fn new(world: &mut World) -> Self {
302        Self {
303            state: SystemState::new(world),
304            view: world.query(),
305            entity: world.query(),
306        }
307    }
308}
309
310impl<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static> Draw<P> for RenderCommandState<P, C>
311where
312    C::Param: ReadOnlySystemParam,
313{
314    /// Prepares the render command to be used. This is called once and only once before the phase
315    /// begins. There may be zero or more [`draw`](RenderCommandState::draw) calls following a call to this function.
316    fn prepare(&mut self, world: &'_ World) {
317        self.view.update_archetypes(world);
318        self.entity.update_archetypes(world);
319    }
320
321    /// Fetches the ECS parameters for the wrapped [`RenderCommand`] and then renders it.
322    fn draw<'w>(
323        &mut self,
324        world: &'w World,
325        pass: &mut TrackedRenderPass<'w>,
326        view: Entity,
327        item: &P,
328    ) -> Result<(), DrawError> {
329        let param = self.state.get(world).unwrap();
330        let view = match self.view.get_manual(world, view) {
331            Ok(view) => view,
332            Err(err) => match err {
333                QueryEntityError::NotSpawned(_) => return Err(DrawError::ViewEntityNotFound),
334                QueryEntityError::QueryDoesNotMatch(_, _)
335                | QueryEntityError::AliasedMutability(_) => {
336                    return Err(DrawError::InvalidViewQuery)
337                }
338            },
339        };
340
341        let entity = self.entity.get_manual(world, item.entity()).ok();
342        match C::render(item, view, entity, param, pass) {
343            RenderCommandResult::Success | RenderCommandResult::Skip => Ok(()),
344            RenderCommandResult::Failure(reason) => Err(DrawError::RenderCommandFailure(reason)),
345        }
346    }
347}
348
349/// Registers a [`RenderCommand`] as a [`Draw`] function.
350/// They are stored inside the [`DrawFunctions`] resource of the app.
351pub trait AddRenderCommand {
352    /// Adds the [`RenderCommand`] for the specified render phase to the app.
353    fn add_render_command<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static>(
354        &mut self,
355    ) -> &mut Self
356    where
357        C::Param: ReadOnlySystemParam;
358}
359
360impl AddRenderCommand for SubApp {
361    fn add_render_command<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static>(
362        &mut self,
363    ) -> &mut Self
364    where
365        C::Param: ReadOnlySystemParam,
366    {
367        let draw_function = RenderCommandState::<P, C>::new(self.world_mut());
368        let draw_functions = self
369            .world()
370            .get_resource::<DrawFunctions<P>>()
371            .unwrap_or_else(|| {
372                {
    ::core::panicking::panic_fmt(format_args!("DrawFunctions<{0}> must be added to the world as a resource before adding render commands to it",
            core::any::type_name::<P>()));
};panic!(
373                    "DrawFunctions<{}> must be added to the world as a resource \
374                     before adding render commands to it",
375                    core::any::type_name::<P>(),
376                );
377            });
378        draw_functions.write().add_with::<C, _>(draw_function);
379        self
380    }
381}
382
383impl AddRenderCommand for App {
384    fn add_render_command<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static>(
385        &mut self,
386    ) -> &mut Self
387    where
388        C::Param: ReadOnlySystemParam,
389    {
390        SubApp::add_render_command::<P, C>(self.main_mut());
391        self
392    }
393}