maplibre/render/render_phase/
draw.rs

1use std::marker::PhantomData;
2
3use crate::{render::resource::TrackedRenderPass, tcs::world::World};
4
5/// A draw function which is used to draw a specific [`PhaseItem`].
6///
7/// They are the the general form of drawing items, whereas [`RenderCommands`](RenderCommand)
8/// are more modular.
9pub trait Draw<P: PhaseItem>: 'static {
10    /// Draws the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
11    fn draw<'w>(&self, pass: &mut TrackedRenderPass<'w>, wold: &'w World, item: &P);
12}
13
14/// An item which will be drawn to the screen. A phase item should be queued up for rendering
15/// during the [`RenderStageLabel::Queue`](crate::RenderStageLabel::Queue) stage.
16/// Afterwards it will be sorted and rendered automatically  in the
17/// [`RenderStageLabel::PhaseSort`](crate::RenderStageLabel::PhaseSort) stage and
18/// [`RenderStageLabel::Render`](crate::RenderStageLabel::Render) stage, respectively.
19pub trait PhaseItem {
20    /// The type used for ordering the items. The smallest values are drawn first.
21    type SortKey: Ord;
22    /// Determines the order in which the items are drawn during the corresponding [`RenderPhase`](super::RenderPhase).
23    fn sort_key(&self) -> Self::SortKey;
24
25    fn draw_function(&self) -> &dyn Draw<Self>;
26}
27
28/// [`RenderCommand`] is a trait that runs an ECS query and produces one or more
29/// [`TrackedRenderPass`] calls. Types implementing this trait can be composed (as tuples).
30///
31/// They can be registered as a [`Draw`] function via the
32/// [`AddRenderCommand::add_render_command`] method.
33///
34/// # Example
35/// The `DrawPbr` draw function is created from the following render command
36/// tuple.  Const generics are used to set specific bind group locations:
37///
38/// ```ignore
39/// pub type DrawPbr = (
40///     SetItemPipeline,
41///     SetMeshViewBindGroup<0>,
42///     SetStandardMaterialBindGroup<1>,
43///     SetTransformBindGroup<2>,
44///     DrawMesh,
45/// );
46/// ```
47pub trait RenderCommand<P: PhaseItem> {
48    /// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`].
49    // TODO: reorder the arguments to match Node and Draw
50    fn render<'w>(
51        world: &'w World,
52        item: &P,
53        pass: &mut TrackedRenderPass<'w>,
54    ) -> RenderCommandResult;
55}
56
57pub enum RenderCommandResult {
58    Success,
59    Failure,
60}
61
62macro_rules! render_command_tuple_impl {
63    ($($name: ident),*) => {
64        impl<P: PhaseItem, $($name: RenderCommand<P>),*> RenderCommand<P> for ($($name,)*) {
65            #[allow(non_snake_case)]
66            fn render<'w>(
67                world: &'w World,
68                item: &P,
69                pass: &mut TrackedRenderPass<'w>,
70            ) -> RenderCommandResult{
71                $(if let RenderCommandResult::Failure = $name::render(world, item, pass) {
72                    return RenderCommandResult::Failure;
73                })*
74                RenderCommandResult::Success
75            }
76        }
77    };
78}
79
80render_command_tuple_impl!(C0);
81render_command_tuple_impl!(C0, C1);
82render_command_tuple_impl!(C0, C1, C2);
83render_command_tuple_impl!(C0, C1, C2, C3);
84render_command_tuple_impl!(C0, C1, C2, C3, C4);
85
86pub struct DrawState<C, P> {
87    phantom_p: PhantomData<P>,
88    phantom_c: PhantomData<C>,
89}
90
91impl<C, P> DrawState<C, P> {
92    pub(crate) fn new() -> Self {
93        DrawState {
94            phantom_p: Default::default(),
95            phantom_c: Default::default(),
96        }
97    }
98}
99
100impl<P: 'static, C: 'static> Draw<P> for DrawState<P, C>
101where
102    P: PhaseItem,
103    C: RenderCommand<P>,
104{
105    /// Prepares data for the wrapped [`RenderCommand`] and then renders it.
106    fn draw<'w>(&self, pass: &mut TrackedRenderPass<'w>, world: &'w World, item: &P) {
107        C::render(world, item, pass);
108    }
109}