1use 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
25pub trait Drawer: TypePath + Component + Sized {
28 type Vertex: Vertex;
30
31 type ExtractParam: ReadOnlySystemParam;
33 type ExtractData: ReadOnlyQueryData;
35 type ExtractFilter: QueryFilter;
37
38 type DrawParam: ReadOnlySystemParam;
40
41 fn extract(
43 drawer: DrawerExtract<Self>,
44 param: &SystemParamItem<Self::ExtractParam>,
45 query: QueryItem<Self::ExtractData>,
46 );
47
48 fn draw(&mut self, param: &SystemParamItem<Self::DrawParam>, queuer: &impl VertexQueuer<Vertex = Self::Vertex>);
50}
51
52pub enum DrawerExtract<'a, T: Drawer> {
54 Borrowed(&'a mut T),
56 Spawn(&'a mut Option<T>),
58}
59
60impl<T: Drawer> DrawerExtract<'_, T> {
61 #[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 #[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
80pub trait VertexQueuer {
82 type Vertex: Vertex;
84
85 fn data(&self, vertices: impl Transfer<Self::Vertex>) -> u32;
88
89 fn request(&self, layer: f32, key: <Self::Vertex as Vertex>::PipelineKey, indices: impl Transfer<u32>);
92}
93
94#[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 #[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), ¶m, data)
126 } else {
127 let mut extract = None;
128 T::extract(DrawerExtract::Spawn(&mut extract), ¶m, 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(¶m, &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}