flow_ngin/data_structures/
block.rs1use crate::{
8 context::{Context, GPUResource}, data_structures::{
9 instance::Instance,
10 model::{self},
11 }, pick::PickId, render::{Instanced, Render}, resources::{self, pick::load_pick_model}
12};
13use cgmath::{One, Rotation3, Zero};
14use wgpu::{Device, util::DeviceExt};
15
16pub struct BuildingBlocks {
22 pub id: PickId,
24 pub obj_model: model::Model,
25 #[allow(dead_code)]
27 obj_file: String,
28 instances: Vec<Instance>,
29 instance_buffer: wgpu::Buffer,
30 buffer_size_needs_change: bool,
31}
32
33impl AsRef<BuildingBlocks> for BuildingBlocks {
34 fn as_ref(&self) -> &BuildingBlocks {
35 self
36 }
37}
38
39impl BuildingBlocks {
40 pub async fn new(
41 id: impl Into<PickId>,
42 queue: &wgpu::Queue,
43 device: &wgpu::Device,
44 start_position: cgmath::Vector3<f32>,
45 start_rotation: cgmath::Quaternion<f32>,
46 amount: usize,
47 obj_file: &str,
48 ) -> Self {
49 let obj_model = resources::load_model_obj(obj_file, &device, &queue).await;
50 if let Err(e) = obj_model {
51 panic!("Error failed to load model: {}", e);
52 }
53 let obj_model = obj_model.unwrap();
54
55 let instances = (0..amount)
56 .map(|_| {
57 let mut instance = Instance::new();
58 instance.position = start_position;
59 let rotation = if start_position.is_zero() {
60 cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), cgmath::Deg(0.0))
61 } else {
62 start_rotation
63 };
64 instance.rotation = rotation;
65 instance
66 })
67 .collect::<Vec<_>>();
68
69 let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
70 let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
71 label: Some("Instance Buffer"),
72 contents: bytemuck::cast_slice(&instance_data),
73 usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
74 });
75
76 Self {
77 obj_model,
78 instances,
79 obj_file: obj_file.to_string(),
80 instance_buffer,
81 id: id.into(),
83 buffer_size_needs_change: false,
84 }
85 }
86
87 pub fn instances(&self) -> &Vec<Instance> {
89 &self.instances
90 }
91
92 pub fn instances_mut(&mut self) -> &mut Vec<Instance> {
95 self.buffer_size_needs_change = true;
96 &mut self.instances
97 }
98
99 pub fn instances_mut_size_unchanged(&mut self) -> &mut [Instance] {
100 self.instances.as_mut_slice()
101 }
102
103 pub fn add_instance(&mut self, instance: Instance) {
104 self.instances.push(instance);
105 self.buffer_size_needs_change = true;
106 }
107
108 pub fn add_instances(&mut self, mut instances: Vec<Instance>) {
109 self.instances.append(&mut instances);
110 self.buffer_size_needs_change = true;
111 }
112
113 pub async fn mk_multiple(
119 queue: &wgpu::Queue,
120 device: &wgpu::Device,
121 amount: usize,
122 descr: &[(PickId, &'static str)],
123 ) -> Vec<BuildingBlocks> {
124 let futures = descr.into_iter().map(|(id, file_name)| {
125 BuildingBlocks::new(
126 *id,
127 queue,
128 device,
129 cgmath::Vector3::zero(),
130 cgmath::Quaternion::one(),
131 amount,
132 file_name,
133 )
134 });
135 futures::future::join_all(futures).await
136 }
137
138 pub fn to_clickable(&self, device: &Device, id: PickId) -> Self {
149 let obj_model = load_pick_model(device, id, self.obj_model.meshes.clone()).unwrap();
150
151 let instance_data = self
152 .instances
153 .iter()
154 .map(Instance::to_raw)
155 .collect::<Vec<_>>();
156 let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
157 label: Some("Instance Buffer for Picking"),
158 contents: bytemuck::cast_slice(&instance_data),
159 usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
160 });
161
162 Self {
163 obj_model: obj_model,
164 obj_file: self.obj_file.clone(),
165 instances: self.instances.clone(),
166 instance_buffer,
167 id,
168 buffer_size_needs_change: false,
169 }
170 }
171
172 pub fn clear_first(&mut self, amount: usize, ctx: &Context) {
173 self.buffer_size_needs_change = true;
174 self.instances.drain(0..amount);
175 self.write_to_buffer(&ctx.queue, &ctx.device);
176 }
177
178 pub fn clear_at(&mut self, from: usize, to: usize, ctx: &Context) {
179 self.buffer_size_needs_change = true;
180 self.instances.drain(from..to);
181 self.write_to_buffer(&ctx.queue, &ctx.device);
182 }
183
184 pub fn to_instanced(&self) -> Instanced<'_> {
186 Instanced {
187 instance: &self.instance_buffer,
188 model: &self.obj_model,
189 amount: self.instances.len(),
190 front_face: wgpu::FrontFace::Ccw,
191 id: self.id,
192 }
193 }
194}
195
196impl<'a, 'pass> GPUResource<'a, 'pass> for BuildingBlocks {
197 fn write_to_buffer(&mut self, queue: &wgpu::Queue, device: &wgpu::Device) {
198 let raws = self
199 .instances
200 .iter()
201 .map(Instance::to_raw)
202 .collect::<Vec<_>>();
203 if self.buffer_size_needs_change {
204 self.instance_buffer =
205 device
206 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
207 label: Some("Instance Buffer"),
208 contents: bytemuck::cast_slice(&raws),
209 usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
210 });
211 self.buffer_size_needs_change = false;
212 } else {
213 queue
214 .write_buffer(&self.instance_buffer, 0, bytemuck::cast_slice(&raws));
215 }
216 }
217
218 fn get_render(&'a self) -> Render<'a, 'pass> {
219 Render::Default(self.to_instanced())
220 }
221}