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}