1use std::collections::{HashMap, HashSet};
16
17use wgpu::RenderPass;
18
19use crate::{
20 context::{Context, GPUResource},
21 data_structures::{block::BuildingBlocks, model::Model, scene_graph::SceneNode}, pick::PickId,
22};
23
24#[derive(Clone)]
29pub struct Instanced<'a> {
30 pub instance: &'a wgpu::Buffer,
31 pub model: &'a Model,
32 pub front_face: wgpu::FrontFace,
33 pub amount: usize,
34 pub id: PickId,
35}
36
37#[derive(Clone)]
42pub struct Flat<'a> {
43 pub vertex: &'a wgpu::Buffer,
44 pub index: &'a wgpu::Buffer,
45 pub group: &'a wgpu::BindGroup,
46 pub amount: usize,
47 pub id: PickId,
48}
49
50#[derive(Clone)]
55pub struct Geometry<'a> {
56 pub instance: &'a wgpu::Buffer,
57 pub vertex: &'a wgpu::Buffer,
58 pub index: &'a wgpu::Buffer,
59 pub group: &'a wgpu::BindGroup,
60 pub amount: usize,
61 pub id: PickId,
62}
63
64#[derive(Default)]
84pub enum Render<'a, 'pass>
85where
86 'pass: 'a,
87{
88 #[default]
89 None,
90 Default(Instanced<'a>),
91 Defaults(Vec<Instanced<'a>>),
92 Transparent(Instanced<'a>),
93 Transparents(Vec<Instanced<'a>>),
94 GUI(Flat<'a>),
95 Terrain(Geometry<'a>),
96 Composed(Vec<Render<'a, 'pass>>),
97 Custom(Box<dyn 'a + FnOnce(&Context, &mut wgpu::RenderPass<'pass>) -> ()>),
98}
99impl<'a, 'pass> Render<'a, 'pass> {
100 pub(crate) fn map_ids(
106 &self,
107 flow_id: usize,
109 map: &mut HashMap<PickId, HashSet<usize>>,
110 ) {
111 match self {
112 Render::Default(instanced) => {
113 map.entry(instanced.id)
114 .and_modify(|flows| _ = flows.insert(flow_id))
115 .or_insert([flow_id].into());
116 }
117 Render::Defaults(vec) => vec.into_iter().for_each(|instanced| {
118 map.entry(instanced.id)
119 .and_modify(|flows| {
120 flows.insert(flow_id);
121 })
122 .or_insert([flow_id].into());
123 }),
124 Render::Transparents(vec) => vec.into_iter().for_each(|instanced| {
125 map.entry(instanced.id)
126 .and_modify(|flows| {
127 flows.insert(flow_id);
128 })
129 .or_insert([flow_id].into());
130 }),
131 Render::Transparent(instanced) => {
132 map.entry(instanced.id)
133 .and_modify(|flows| _ = flows.insert(flow_id))
134 .or_insert([flow_id].into());
135 }
136 Render::GUI(flat) => {
137 map.entry(flat.id)
138 .and_modify(|flows| _ = flows.insert(flow_id))
139 .or_insert([flow_id].into());
140 }
141 Render::Terrain(flat) => {
142 map.entry(flat.id)
143 .and_modify(|flows| _ = flows.insert(flow_id))
144 .or_insert([flow_id].into());
145 }
146 Render::Composed(renders) => renders
147 .into_iter()
148 .for_each(|render| render.map_ids(flow_id, map)),
149 Render::None | Render::Custom(_) => (),
150 }
151 }
152
153 pub(crate) fn set_pipelines(
154 self,
155 ctx: &Context,
156 render_pass: &mut RenderPass<'pass>,
157 basics: &mut Vec<Instanced<'a>>,
158 trans: &mut Vec<Instanced<'a>>,
159 guis: &mut Vec<Flat<'a>>,
160 terrain: &mut Vec<Geometry<'a>>,
161 customs: &mut Vec<Box<dyn 'a + FnOnce(&Context, &mut wgpu::RenderPass<'pass>) -> ()>>,
162 ) {
163 match self {
164 Render::Default(instanced) => {
165 basics.push(instanced);
166 }
167 Render::Defaults(mut vec) => basics.append(&mut vec),
168 Render::Transparent(instanced) => trans.push(instanced),
169 Render::Transparents(mut vec) => trans.append(&mut vec),
170 Render::GUI(flat) => guis.push(flat),
171 Render::Terrain(flat) => terrain.push(flat),
172 Render::Composed(renders) => renders
173 .into_iter()
174 .map(|render| render.set_pipelines(ctx, render_pass, basics, trans, guis, terrain, customs))
175 .collect(),
176 Render::Custom(f) => customs.push(f),
177 Render::None => (),
178 }
179 }
180
181 pub(crate) fn set_pick_pipelines(
182 self,
183 ctx: &Context,
184 render_pass: &mut RenderPass<'pass>,
185 basics: &mut Vec<Instanced<'a>>,
186 flats: &mut Vec<Flat<'a>>,
187 geoms: &mut Vec<Geometry<'a>>,
188 ) {
189 match self {
190 Render::Default(instanced) => {
191 basics.push(instanced);
192 }
193 Render::Defaults(mut vec) => basics.append(&mut vec),
194 Render::Transparent(instanced) => basics.push(instanced),
195 Render::Transparents(mut vec) => basics.append(&mut vec),
196 Render::GUI(flat) => flats.push(flat),
197 Render::Terrain(flat) => geoms.push(flat),
198 Render::Composed(renders) => renders
199 .into_iter()
200 .map(|render| render.set_pick_pipelines(ctx, render_pass, basics, flats, geoms))
201 .collect(),
202 Render::Custom(_) => (),
204 Render::None => (),
205 }
206 }
207}
208impl<'a, 'pass> From<&'a dyn SceneNode> for Render<'a, 'pass> {
209 fn from(sn: &'a dyn SceneNode) -> Self {
210 Render::Defaults(sn.get_render())
211 }
212}
213impl<'a, 'pass> From<&'a (dyn SceneNode + Send)> for Render<'a, 'pass> {
214 fn from(sn: &'a (dyn SceneNode + Send)) -> Self {
215 Render::Defaults(sn.get_render())
216 }
217}
218impl<'a, 'pass> From<&'a BuildingBlocks> for Render<'a, 'pass> {
219 fn from(blocks: &'a BuildingBlocks) -> Self {
220 blocks.get_render()
221 }
222}
223#[cfg(feature = "integration-tests")]
224impl<'b, 'pass> From<&'b Box<dyn SceneNode>> for Render<'b, 'pass> {
225 fn from(val: &'b Box<dyn SceneNode>) -> Self {
226 Render::from(val.as_ref())
228 }
229}
230#[cfg(feature = "integration-tests")]
231impl<'a, 'pass> From<&'a Box<dyn GPUResource<'a, 'pass> + Send>> for Render<'a, 'pass> {
232 fn from(val: &'a Box<dyn GPUResource<'a, 'pass> + Send>) -> Self {
233 val.get_render()
234 }
235}