hephae_render/
drawer.rs

1//! Defines base drawers that work with vertices and supply various vertex commands.
2
3use std::{marker::PhantomData, sync::PoisonError};
4
5use bevy_ecs::{
6    prelude::*,
7    query::{QueryFilter, QueryItem, ReadOnlyQueryData},
8    system::{ReadOnlySystemParam, StaticSystemParam, SystemParamItem},
9};
10use bevy_reflect::prelude::*;
11use bevy_render::{
12    self, Extract,
13    prelude::*,
14    sync_world::RenderEntity,
15    view::{ExtractedView, RenderVisibleEntities},
16};
17use fixedbitset::FixedBitSet;
18use vec_belt::Transfer;
19
20use crate::{
21    pipeline::{DrawBuffers, VisibleDrawers},
22    vertex::{DrawItems, Vertex},
23};
24
25/// A render world [`Component`] extracted from the main world that will be used to issue draw
26/// requests.
27pub trait Drawer: TypePath + Component + Sized {
28    /// The type of vertex this drawer works with.
29    type Vertex: Vertex;
30
31    /// System parameter to fetch when extracting data from the main world.
32    type ExtractParam: ReadOnlySystemParam;
33    /// Query item to fetch from entities when extracting from those entities to the render world.
34    type ExtractData: ReadOnlyQueryData;
35    /// Additional query filters accompanying [`ExtractData`](Drawer::ExtractData).
36    type ExtractFilter: QueryFilter;
37
38    /// System parameter to fetch when issuing draw requests.
39    type DrawParam: ReadOnlySystemParam;
40
41    /// Extracts an instance of this drawer from matching entities, if available.
42    fn extract(
43        drawer: DrawerExtract<Self>,
44        param: &SystemParamItem<Self::ExtractParam>,
45        query: QueryItem<Self::ExtractData>,
46    );
47
48    /// Issues vertex data and draw requests for the data.
49    fn draw(&mut self, param: &SystemParamItem<Self::DrawParam>, queuer: &impl VertexQueuer<Vertex = Self::Vertex>);
50}
51
52/// Specifies the behavior of [`Drawer::extract`].
53pub enum DrawerExtract<'a, T: Drawer> {
54    /// The render-world component exists, and may be used to optimize allocations.
55    Borrowed(&'a mut T),
56    /// The drawer needs to create a new instance of itself.
57    Spawn(&'a mut Option<T>),
58}
59
60impl<T: Drawer> DrawerExtract<'_, T> {
61    /// Gets a mutable reference to the underlying component, creating a new one if necessary.
62    #[inline]
63    pub fn get_mut(&mut self, new: impl FnOnce() -> T) -> &mut T {
64        match self {
65            Self::Borrowed(value) => value,
66            Self::Spawn(opt) => opt.insert(new()),
67        }
68    }
69
70    /// Gets a mutable reference to the underlying component, creating a new one if necessary.
71    #[inline]
72    pub fn get_or_default(&mut self) -> &mut T
73    where
74        T: Default,
75    {
76        self.get_mut(T::default)
77    }
78}
79
80/// Similar to [`Extend`], except it works with both vertex and index buffers.
81pub trait VertexQueuer {
82    /// The type of vertex this queuer works with.
83    type Vertex: Vertex;
84
85    /// Extends the vertex buffer with the supplied iterator. The returned index should be used as
86    /// offset adder to indices passed to [`request`](VertexQueuer::request).
87    fn data(&self, vertices: impl Transfer<Self::Vertex>) -> u32;
88
89    /// Extends the index buffer with the supplied iterator. Indices should be offset by the index
90    /// returned by [`data`](VertexQueuer::data).
91    fn request(&self, layer: f32, key: <Self::Vertex as Vertex>::PipelineKey, indices: impl Transfer<u32>);
92}
93
94/// Marker component for entities that may extract out [`Drawer`]s to the render world. This *must*
95/// be added to those entities so they'll be calculated in
96/// [`check_visibilities`](crate::vertex::check_visibilities).
97#[derive(Reflect, Component, Copy, Clone)]
98#[reflect(Component, Default)]
99#[require(Visibility)]
100pub struct HasDrawer<T: Drawer>(#[reflect(ignore)] pub PhantomData<fn() -> T>);
101impl<T: Drawer> Default for HasDrawer<T> {
102    #[inline]
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl<T: Drawer> HasDrawer<T> {
109    /// Shortcut for `HasDrawer(PhantomData)`.
110    #[inline]
111    pub const fn new() -> Self {
112        Self(PhantomData)
113    }
114}
115
116pub(crate) fn extract_drawers<T: Drawer>(
117    mut commands: Commands,
118    param: Extract<T::ExtractParam>,
119    query: Extract<Query<(RenderEntity, &ViewVisibility, T::ExtractData), (T::ExtractFilter, With<HasDrawer<T>>)>>,
120    mut target_query: Query<&mut T>,
121) {
122    for (e, &view, data) in &query {
123        if view.get() {
124            if let Ok(mut dst) = target_query.get_mut(e) {
125                T::extract(DrawerExtract::Borrowed(&mut dst), &param, data)
126            } else {
127                let mut extract = None;
128                T::extract(DrawerExtract::Spawn(&mut extract), &param, data);
129
130                if let Some(extract) = extract {
131                    commands.entity(e).insert(extract);
132                }
133            }
134        }
135    }
136}
137
138pub(crate) fn queue_drawers<T: Drawer>(
139    param: StaticSystemParam<T::DrawParam>,
140    buffers: Res<DrawBuffers<T::Vertex>>,
141    mut query: Query<(Entity, &mut T, &DrawItems<T::Vertex>)>,
142    views: Query<(&RenderVisibleEntities, &VisibleDrawers<T::Vertex>), With<ExtractedView>>,
143    mut iterated: Local<FixedBitSet>,
144) {
145    let buffers = buffers.into_inner();
146
147    iterated.clear();
148    for (visible_entities, visible_drawers) in &views {
149        let mut iter = query.iter_many_mut(visible_entities.iter::<With<HasDrawer<T>>>().map(|(e, ..)| e));
150        while let Some((e, mut drawer, items)) = iter.fetch_next() {
151            let index = e.index() as usize;
152            if iterated[index] {
153                continue;
154            }
155
156            iterated.grow_and_insert(index);
157            visible_drawers.0.append([e]);
158
159            drawer.draw(&param, &Queuer { buffers, items });
160        }
161    }
162
163    struct Queuer<'a, T: Vertex> {
164        buffers: &'a DrawBuffers<T>,
165        items: &'a DrawItems<T>,
166    }
167
168    impl<T: Vertex> VertexQueuer for Queuer<'_, T> {
169        type Vertex = T;
170
171        #[inline]
172        fn data(&self, vertices: impl Transfer<T>) -> u32 {
173            self.buffers.vertices.append(vertices) as u32
174        }
175
176        #[inline]
177        fn request(&self, layer: f32, key: T::PipelineKey, indices: impl Transfer<u32>) {
178            let len = indices.len();
179            let offset = self.buffers.indices.append(indices);
180
181            self.items
182                .0
183                .lock()
184                .unwrap_or_else(PoisonError::into_inner)
185                .push((offset..offset + len, layer, key));
186        }
187    }
188}