wde_renderer/assets/bindings/
render_data.rs1use wde_logger::prelude::*;
2
3use crate::prelude::*;
4use bevy::{
5 ecs::system::{
6 StaticSystemParam, SystemParam, SystemParamItem, SystemState,
7 lifetimeless::{SRes, SResMut}
8 },
9 prelude::*
10};
11use std::{any::TypeId, collections::HashMap};
12
13#[derive(Message)]
14pub(crate) struct RenderDataRecreated(pub TypeId);
15
16pub struct RenderDataRegisterPlugin<R: RenderData>(std::marker::PhantomData<R>);
29impl<R: RenderData> Default for RenderDataRegisterPlugin<R> {
30 fn default() -> Self {
31 RenderDataRegisterPlugin(std::marker::PhantomData)
32 }
33}
34impl<R: RenderData + TypePath + Sync + Send + Clone + Asset> Plugin
35 for RenderDataRegisterPlugin<R>
36{
37 fn build(&self, app: &mut App) {
38 app.add_message::<RenderDataRecreated>();
39
40 app.init_asset::<RenderDataHolder<R>>();
42
43 app.add_plugins(RenderAssetsPlugin::<GpuRenderData<R>>::default());
45 }
46
47 fn finish(&self, app: &mut App) {
48 let builder = {
50 let mut builder = RenderDataBuilder::default();
51 let mut state: SystemState<R::Params> = SystemState::new(app.world_mut());
52 let mut params = state.get_mut(app.world_mut());
53 R::describe(&mut params, &mut builder);
54 builder
55 };
56 let handle = app
57 .world_mut()
58 .resource::<AssetServer>()
59 .add(RenderDataHolder::<R> {
60 _phantom: std::marker::PhantomData,
61 builder
62 });
63 app.world_mut()
64 .commands()
65 .insert_resource(RenderDataHolderHandle(handle));
66
67 let recreate = {
69 let mut state: SystemState<R::Params> = SystemState::new(app.world_mut());
70 let params = state.get_mut(app.world_mut());
71 R::recreate(¶ms).is_some()
72 };
73 if recreate {
74 app.add_systems(Update, recreate_system::<R>);
75 }
76 }
77}
78
79fn recreate_system<R: RenderData + TypePath + Sync + Send + 'static>(
80 mut params: StaticSystemParam<R::Params>,
81 asset_server: Res<AssetServer>,
82 mut commands: Commands,
83 mut recreate_version: MessageWriter<RenderDataRecreated>
84) {
85 if let Some(true) = R::recreate(¶ms) {
86 debug!("Recreating render data {}.", std::any::type_name::<R>());
87
88 let builder = {
90 let mut builder = RenderDataBuilder::default();
91 R::describe(&mut params, &mut builder);
92 builder
93 };
94 let new_handle = asset_server.add(RenderDataHolder::<R> {
95 _phantom: std::marker::PhantomData,
96 builder
97 });
98 commands.insert_resource(RenderDataHolderHandle(new_handle));
99
100 recreate_version.write(RenderDataRecreated(TypeId::of::<R>()));
102 }
103}
104
105#[derive(Default, Clone)]
109pub struct RenderDataBuilder {
110 binding_to_index: HashMap<u32, (usize, usize)>, buffers: Vec<Buffer>,
112 textures: Vec<Texture>
113}
114impl RenderDataBuilder {
115 pub fn add_buffer(&mut self, binding: u32, buffer: Buffer) -> &mut Self {
117 self.buffers.push(buffer);
118 self.binding_to_index
119 .insert(binding, (0, self.buffers.len() - 1));
120 self
121 }
122 pub fn add_texture(&mut self, binding: u32, texture: Texture) -> &mut Self {
124 self.textures.push(texture);
125 self.binding_to_index
126 .insert(binding, (1, self.textures.len() - 1));
127 self
128 }
129}
130
131pub trait RenderData {
140 type Params: SystemParam;
141
142 fn describe(params: &mut SystemParamItem<Self::Params>, builder: &mut RenderDataBuilder);
147 fn recreate(_params: &SystemParamItem<Self::Params>) -> Option<bool> {
149 None
150 }
151}
152
153#[allow(unused)]
155#[derive(Resource)]
156struct RenderDataHolderHandle<R: RenderData + TypePath + Sync + Send>(Handle<RenderDataHolder<R>>);
157
158#[derive(Asset, Clone, TypePath)]
159pub struct RenderDataHolder<R: RenderData + TypePath + Sync + Send> {
160 _phantom: std::marker::PhantomData<R>,
161 builder: RenderDataBuilder
162}
163
164pub type SRenderData<T> = SRes<RenderAssets<GpuRenderData<T>>>;
167pub type SRenderDataMut<T> = SResMut<RenderAssets<GpuRenderData<T>>>;
169
170pub type ResRenderData<'w, M> = Res<'w, RenderAssets<GpuRenderData<M>>>;
172pub type ResMutRenderData<'w, M> = ResMut<'w, RenderAssets<GpuRenderData<M>>>;
174
175pub struct GpuRenderData<R: RenderData> {
178 _phantom: std::marker::PhantomData<R>,
179 builder: RenderDataBuilder,
180 buffers: Vec<Handle<Buffer>>,
181 textures: Vec<Handle<Texture>>
182}
183impl<R: RenderData> GpuRenderData<R> {
184 pub fn get_buffer(&self, binding: u32) -> Option<Handle<Buffer>> {
186 self.builder
187 .binding_to_index
188 .get(&binding)
189 .and_then(|(ty, idx)| {
190 debug_assert!(
191 *ty == 0,
192 "Tried to get buffer for binding {}, but it was a texture",
193 binding
194 );
195 self.buffers.get(*idx).cloned()
196 })
197 }
198 pub fn get_texture(&self, binding: u32) -> Option<Handle<Texture>> {
200 self.builder
201 .binding_to_index
202 .get(&binding)
203 .and_then(|(ty, idx)| {
204 debug_assert!(
205 *ty == 1,
206 "Tried to get texture for binding {}, but it was a buffer",
207 binding
208 );
209 self.textures.get(*idx).cloned()
210 })
211 }
212}
213impl<R: RenderData + Clone + Asset> RenderAsset for GpuRenderData<R> {
214 type SourceAsset = RenderDataHolder<R>;
215 type Params = SRes<AssetServer>;
216
217 fn prepare(
218 asset: Self::SourceAsset,
219 asset_server: &mut SystemParamItem<Self::Params>
220 ) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
221 debug!(
222 "Preparing render binding {} GPU resources.",
223 std::any::type_name::<R>()
224 );
225 let mut buffers = Vec::new();
226 let mut textures = Vec::new();
227 let mut updated_builder = RenderDataBuilder::default();
228 for (binding, (ty, idx)) in asset.builder.binding_to_index.iter() {
229 match ty {
230 0 => {
231 let mut buffer = asset.builder.buffers.get(*idx).unwrap().clone();
233 let handle = asset_server.add(buffer.clone());
234 buffers.push(handle);
235
236 buffer.content = None; updated_builder.add_buffer(*binding, buffer);
238 }
239 1 => {
240 let mut texture = asset.builder.textures.get(*idx).unwrap().clone();
242 let handle = asset_server.add(texture.clone());
243 textures.push(handle);
244
245 texture.data = vec![]; updated_builder.add_texture(*binding, texture);
247 }
248 _ => unreachable!()
249 }
250 }
251 Ok(GpuRenderData {
252 _phantom: std::marker::PhantomData,
253 builder: updated_builder,
254 buffers,
255 textures
256 })
257 }
258}