1use std::collections::hash_map::Entry;
2use std::collections::{BTreeMap, HashMap};
3use std::f32::consts::PI;
4
5use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer};
6use rectangle_pack::{
7 contains_smallest_box, pack_rects, volume_heuristic, GroupedRectsToPlace, RectToInsert,
8 TargetBin,
9};
10use wgpu::util::DeviceExt;
11use wgpu::{
12 BindGroup, BindGroupLayout, Color, CommandEncoder, Device, Queue, RenderPipeline,
13 SamplerDescriptor, SurfaceConfiguration, TextureView,
14};
15use wgpu_noboiler::buffer::{BufferCreator, SimpleBuffer};
16use wgpu_noboiler::render_pass::RenderPassCreator;
17use wgpu_noboiler::render_pipeline::RenderPipelineCreator;
18use wgpu_noboiler::vertex::Vertex;
19
20use crate::render::depth_buffer::DepthBuffer;
21use crate::render::instance::{Instance, TextureInstance};
22use crate::render::vertex::Vertex as OwnVertex;
23use crate::shape::image::Image;
24use crate::shape::oval::Oval;
25use crate::shape::rect::Rect;
26use crate::shape::shapes::BasicShape;
27
28pub struct ShapeRenderer {
30 shape_render_pipeline: RenderPipeline,
31 texture_render_pipeline: RenderPipeline,
32
33 recs: Vec<Rect>,
34 ovals: Vec<Oval>,
35 images: Vec<Image>,
36
37 frame_group_layout: BindGroupLayout,
38 frame_size: (f32, f32),
39 frame_offset: (f32, f32),
40
41 background_color: Color,
42
43 depth_texture: DepthBuffer,
44
45 texture_group_layout: BindGroupLayout,
46 texture: Option<TextureView>,
47 texture_size: u32,
48 textures: Vec<DynamicImage>,
49 textures_cords: Vec<((f32, f32), (f32, f32))>,
50
51 rect_vertex_buffer: SimpleBuffer,
52 rect_indices_buffer: SimpleBuffer,
53}
54
55impl ShapeRenderer {
56 pub fn new(device: &Device, config: &SurfaceConfiguration) -> ShapeRenderer {
61 let frame_size_group_layout =
62 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
63 entries: &[
64 wgpu::BindGroupLayoutEntry {
65 binding: 0,
66 visibility: wgpu::ShaderStages::VERTEX,
67 ty: wgpu::BindingType::Buffer {
68 ty: wgpu::BufferBindingType::Uniform,
69 has_dynamic_offset: false,
70 min_binding_size: None,
71 },
72 count: None,
73 },
74 wgpu::BindGroupLayoutEntry {
75 binding: 1,
76 visibility: wgpu::ShaderStages::VERTEX,
77 ty: wgpu::BindingType::Buffer {
78 ty: wgpu::BufferBindingType::Uniform,
79 has_dynamic_offset: false,
80 min_binding_size: None,
81 },
82 count: None,
83 },
84 ],
85 label: Some("Frame Bind group"),
86 });
87
88 let texture_bind_group_layout =
89 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
90 entries: &[
91 wgpu::BindGroupLayoutEntry {
92 binding: 0,
93 visibility: wgpu::ShaderStages::FRAGMENT,
94 ty: wgpu::BindingType::Texture {
95 multisampled: false,
96 view_dimension: wgpu::TextureViewDimension::D2,
97 sample_type: wgpu::TextureSampleType::Float { filterable: true },
98 },
99 count: None,
100 },
101 wgpu::BindGroupLayoutEntry {
102 binding: 1,
103 visibility: wgpu::ShaderStages::FRAGMENT,
104 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
107 count: None,
108 },
109 ],
110 label: Some("texture_bind_group_layout"),
111 });
112
113 let shape_render_pipeline = RenderPipelineCreator::from_shader_code(
114 include_str!("../resources/shape_shader.wgsl"),
115 device,
116 config,
117 )
118 .add_bind_group(&frame_size_group_layout)
119 .add_vertex_buffer(OwnVertex::descriptor())
120 .add_vertex_buffer(Instance::descriptor())
121 .depth_stencil(wgpu::DepthStencilState {
122 format: DepthBuffer::DEPTH_FORMAT,
123 depth_write_enabled: true,
124 depth_compare: wgpu::CompareFunction::Less,
125 stencil: wgpu::StencilState::default(),
126 bias: wgpu::DepthBiasState::default(),
127 })
128 .build();
129
130 let texture_render_pipeline = RenderPipelineCreator::from_shader_code(
131 include_str!("../resources/texture_shader.wgsl"),
132 device,
133 config,
134 )
135 .add_bind_group(&frame_size_group_layout)
136 .add_bind_group(&texture_bind_group_layout)
137 .add_vertex_buffer(OwnVertex::descriptor())
138 .add_vertex_buffer(TextureInstance::descriptor())
139 .depth_stencil(wgpu::DepthStencilState {
140 format: DepthBuffer::DEPTH_FORMAT,
141 depth_write_enabled: true,
142 depth_compare: wgpu::CompareFunction::Less,
143 stencil: wgpu::StencilState::default(),
144 bias: wgpu::DepthBiasState::default(),
145 })
146 .build();
147
148 let rect_vertex_buffer = BufferCreator::vertex(device)
149 .label("Rect VertexBuffer")
150 .data(vec![
151 OwnVertex {
152 position: [1.0, 1.0],
153 },
154 OwnVertex {
155 position: [-1.0, 1.0],
156 },
157 OwnVertex {
158 position: [-1.0, -1.0],
159 },
160 OwnVertex {
161 position: [1.0, -1.0],
162 },
163 ])
164 .build();
165
166 let rect_indices_buffer = BufferCreator::indices(device)
167 .label("Rect IndicesBuffer")
168 .data(vec![0, 1, 2, 0, 2, 3])
169 .build();
170
171 ShapeRenderer {
172 shape_render_pipeline,
173 texture_render_pipeline,
174
175 recs: vec![],
176 ovals: vec![],
177 images: vec![],
178
179 frame_group_layout: frame_size_group_layout,
180 frame_size: (800.0, 600.0),
181 frame_offset: (0.0, 0.0),
182
183 background_color: Color::WHITE,
184
185 depth_texture: DepthBuffer::create_depth_texture(device, config, "depth_texture"),
186
187 texture_group_layout: texture_bind_group_layout,
188 texture: None,
189 texture_size: 512,
190 textures: vec![],
191 textures_cords: vec![],
192 rect_vertex_buffer,
193 rect_indices_buffer,
194 }
195 }
196
197 fn frame_bind_group(&self, device: &Device) -> BindGroup {
198 let frame_size_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
199 label: Some("Frame size Buffer"),
200 contents: bytemuck::cast_slice(&[self.frame_size.0, self.frame_size.1]),
201 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
202 });
203
204 let frame_offset_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
205 label: Some("Frame offset Buffer"),
206 contents: bytemuck::cast_slice(&[self.frame_offset.0, self.frame_offset.1]),
207 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
208 });
209
210 device.create_bind_group(&wgpu::BindGroupDescriptor {
211 layout: &self.frame_group_layout,
212 entries: &[
213 wgpu::BindGroupEntry {
214 binding: 0,
215 resource: frame_size_buffer.as_entire_binding(),
216 },
217 wgpu::BindGroupEntry {
218 binding: 1,
219 resource: frame_offset_buffer.as_entire_binding(),
220 },
221 ],
222 label: Some("frame_size_bind_group"),
223 })
224 }
225
226 fn texture_bind_group(&self, device: &Device) -> Option<BindGroup> {
227 self.texture.as_ref()?;
228
229 Some(device.create_bind_group(&wgpu::BindGroupDescriptor {
230 layout: &self.texture_group_layout,
231 entries: &[
232 wgpu::BindGroupEntry {
233 binding: 0,
234 resource: wgpu::BindingResource::TextureView(self.texture.as_ref().unwrap()),
235 },
236 wgpu::BindGroupEntry {
237 binding: 1,
238 resource: wgpu::BindingResource::Sampler(
239 &device.create_sampler(&SamplerDescriptor::default()),
240 ),
241 },
242 ],
243 label: Some("diffuse_bind_group"),
244 }))
245 }
246
247 pub fn render<'a, 'b: 'a>(
249 &'b self,
250 encoder: &mut CommandEncoder,
251 texture_view: &TextureView,
252 device: &Device,
253 ) {
254 let rect_instance_buffer = self.generate_rect_buffer(device);
255 let oval_buffers = self.generate_oval_buffer(device);
256 let image_instance_buffer = self.generate_image_buffer(device);
257
258 let frame_bind_group = self.frame_bind_group(device);
259 let texture_bind_group = self.texture_bind_group(device);
260
261 let mut render_pass = RenderPassCreator::new(texture_view)
262 .depth_stencil_attachment(wgpu::RenderPassDepthStencilAttachment {
263 view: &self.depth_texture.view,
264 depth_ops: Some(wgpu::Operations {
265 load: wgpu::LoadOp::Clear(1.0),
266 store: true,
267 }),
268 stencil_ops: None,
269 })
270 .clear_color(self.background_color)
271 .build(encoder);
272
273 render_pass.set_pipeline(&self.shape_render_pipeline);
274 render_pass.set_bind_group(0, &frame_bind_group, &[]);
275
276 render_pass.set_vertex_buffer(0, self.rect_vertex_buffer.slice());
278 render_pass.set_index_buffer(self.rect_indices_buffer.slice(), wgpu::IndexFormat::Uint32);
279
280 render_pass.set_vertex_buffer(1, rect_instance_buffer.slice());
281
282 render_pass.draw_indexed(
283 0..self.rect_indices_buffer.size(),
284 0,
285 0..rect_instance_buffer.size(),
286 );
287
288 for InstanceBufferGroup(oval_vertex_buffer, oval_indices_buffer, oval_instance_buffer) in
291 &oval_buffers
292 {
293 render_pass.set_vertex_buffer(0, oval_vertex_buffer.slice());
294 render_pass.set_index_buffer(oval_indices_buffer.slice(), wgpu::IndexFormat::Uint32);
295
296 render_pass.set_vertex_buffer(1, oval_instance_buffer.slice());
297
298 render_pass.draw_indexed(
299 0..oval_indices_buffer.size(),
300 0,
301 0..oval_instance_buffer.size(),
302 );
303 }
304
305 if texture_bind_group.is_none() {
308 return;
309 }
310
311 render_pass.set_pipeline(&self.texture_render_pipeline);
312 render_pass.set_bind_group(0, &frame_bind_group, &[]);
313 render_pass.set_bind_group(1, texture_bind_group.as_ref().unwrap(), &[]);
314
315 render_pass.set_vertex_buffer(0, self.rect_vertex_buffer.slice());
316 render_pass.set_index_buffer(self.rect_indices_buffer.slice(), wgpu::IndexFormat::Uint32);
317
318 render_pass.set_vertex_buffer(1, image_instance_buffer.slice());
319
320 render_pass.draw_indexed(
321 0..self.rect_indices_buffer.size(),
322 0,
323 0..image_instance_buffer.size(),
324 );
325 }
326
327 pub fn clear(&mut self) {
329 self.recs.clear();
330 self.ovals.clear();
331 self.images.clear();
332 }
333
334 pub fn set_frame_size(&mut self, frame_size: (f32, f32)) -> &mut Self {
336 self.frame_size = frame_size;
337 self
338 }
339
340 pub fn frame_size(&self) -> (f32, f32) {
346 self.frame_size
347 }
348
349 pub fn set_frame_offset(&mut self, frame_offset: (f32, f32)) -> &mut Self {
351 self.frame_offset = frame_offset;
352 self
353 }
354
355 pub fn frame_offset(&self) -> (f32, f32) {
357 self.frame_offset
358 }
359
360 pub fn resize(&mut self, device: &Device, config: &SurfaceConfiguration) -> &mut Self {
362 self.depth_texture = DepthBuffer::create_depth_texture(device, config, "depth_texture");
363 self
364 }
365
366 pub fn background_color(&mut self, background_color: Color) -> &mut Self {
368 self.background_color = background_color;
369 self
370 }
371
372 pub fn rect(&mut self) -> &mut Rect {
374 self.recs.push(Rect::default());
375 self.recs.last_mut().unwrap()
376 }
377
378 fn generate_rect_buffer(&self, device: &Device) -> SimpleBuffer {
379 let instances: Vec<_> = self.recs.iter().map(|rect| rect.to_instance()).collect();
380
381 let instances_buffer = BufferCreator::vertex(device)
382 .label("Rect InstanceBuffer")
383 .data(instances)
384 .build();
385
386 instances_buffer
387 }
388
389 pub fn oval(&mut self) -> &mut Oval {
391 self.ovals.push(Oval::default());
392 self.ovals.last_mut().unwrap()
393 }
394
395 fn generate_oval_buffer(&self, device: &Device) -> Vec<InstanceBufferGroup> {
396 let mut ovals = HashMap::<u32, Vec<&Oval>>::new();
397
398 for oval in &self.ovals {
399 if let Entry::Vacant(e) = ovals.entry(oval.detail) {
400 e.insert(vec![oval]);
401 } else {
402 ovals.get_mut(&oval.detail).unwrap().push(oval);
403 }
404 }
405
406 let mut instance_buffer_groups = vec![];
407
408 for (detail, ovals) in ovals {
409 let vertices: Vec<_> = (0..detail)
410 .map(|i| {
411 let angle = PI * 2.0 / detail as f32 * i as f32;
412
413 OwnVertex {
414 position: [angle.cos(), angle.sin()],
415 }
416 })
417 .collect();
418
419 let vertex_buffer = BufferCreator::vertex(device)
420 .label("Rect VertexBuffer")
421 .data(vertices)
422 .build();
423
424 let indices: Vec<_> = (0..(detail as i32 - 2))
425 .flat_map(|i| [0, i + 1, i + 2])
426 .collect();
427
428 let indices_buffer = BufferCreator::indices(device)
429 .label("Rect IndicesBuffer")
430 .data(indices)
431 .build();
432
433 let instances: Vec<_> = ovals.iter().map(|oval| oval.to_instance()).collect();
434
435 let instances_buffer = BufferCreator::vertex(device)
436 .label("Rect InstanceBuffer")
437 .data(instances)
438 .build();
439
440 instance_buffer_groups.push(InstanceBufferGroup(
441 vertex_buffer,
442 indices_buffer,
443 instances_buffer,
444 ));
445 }
446
447 instance_buffer_groups
448 }
449
450 pub fn image(&mut self, texture_index: usize) -> &mut Image {
452 let mut image = Image::default();
453 match self.textures_cords.get(texture_index) {
454 None => {
455 println!("No texture with the id: {} could be found", texture_index);
456 }
457 Some(cords) => {
458 image.texture_pos = cords.0;
459 image.texture_scale = cords.1;
460 }
461 };
462
463 self.images.push(image);
464 self.images.last_mut().unwrap()
465 }
466
467 fn generate_image_buffer(&self, device: &Device) -> SimpleBuffer {
468 let instances: Vec<_> = self
469 .images
470 .iter()
471 .map(|texture| texture.to_instance())
472 .collect();
473
474 let instances_buffer = BufferCreator::vertex(device)
475 .label("Rect InstanceBuffer")
476 .data(instances)
477 .build();
478
479 instances_buffer
480 }
481
482 pub fn add_texture_from_bytes(
483 &mut self,
484 bytes: &[u8],
485 device: &Device,
486 queue: &Queue,
487 ) -> &mut Self {
488 self.textures.push(image::load_from_memory(bytes).unwrap());
489
490 self.upload_textures(device, queue);
491
492 self
493 }
494
495 pub fn add_textures_from_bytes(
497 &mut self,
498 bytes: &Vec<&[u8]>,
499 device: &Device,
500 queue: &Queue,
501 ) -> &mut Self {
502 for bytes in bytes {
503 self.textures.push(image::load_from_memory(bytes).unwrap());
504 }
505
506 self.upload_textures(device, queue);
507
508 self
509 }
510
511 fn upload_textures(&mut self, device: &Device, queue: &Queue) {
513 let mut rects_to_place: GroupedRectsToPlace<usize, usize> = GroupedRectsToPlace::new();
514
515 for (index, image) in self.textures.iter().enumerate() {
516 let dimensions = image.dimensions();
517
518 rects_to_place.push_rect(
519 index,
520 None,
521 RectToInsert::new(dimensions.0, dimensions.1, 1),
522 );
523 }
524
525 let mut target_bins = BTreeMap::new();
526 target_bins.insert(0, TargetBin::new(self.texture_size, self.texture_size, 1));
527
528 let rectangle_placements = pack_rects(
529 &rects_to_place,
530 &mut target_bins,
531 &volume_heuristic,
532 &contains_smallest_box,
533 );
534
535 let rectangle_placements = match rectangle_placements {
536 Ok(rectangle_pack) => rectangle_pack,
537 Err(_) => {
538 self.texture_size *= 2;
539 self.upload_textures(device, queue);
540
541 return;
542 }
543 };
544
545 self.textures_cords.clear();
546 let mut buffer = ImageBuffer::new(self.texture_size, self.texture_size);
547
548 for (index, (_, location)) in rectangle_placements.packed_locations() {
549 buffer
550 .copy_from(
551 self.textures.get(*index).unwrap(),
552 location.x(),
553 location.y(),
554 )
555 .expect("TODO: panic message");
556
557 self.textures_cords.push((
558 (
559 location.x() as f32 / self.texture_size as f32,
560 location.y() as f32 / self.texture_size as f32,
561 ),
562 (
563 location.width() as f32 / self.texture_size as f32,
564 location.height() as f32 / self.texture_size as f32,
565 ),
566 ))
567 }
568
569 let dimensions = buffer.dimensions();
570
571 let texture_size = wgpu::Extent3d {
572 width: dimensions.0,
573 height: dimensions.1,
574 depth_or_array_layers: 1,
575 };
576
577 let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor {
578 size: texture_size,
581 mip_level_count: 1, sample_count: 1,
583 dimension: wgpu::TextureDimension::D2,
584 format: wgpu::TextureFormat::Rgba8Unorm,
586 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
589 label: Some("diffuse_texture"),
590 view_formats: &[],
591 });
592
593 queue.write_texture(
594 wgpu::ImageCopyTexture {
596 texture: &diffuse_texture,
597 mip_level: 0,
598 origin: wgpu::Origin3d::ZERO,
599 aspect: wgpu::TextureAspect::All,
600 },
601 &buffer,
603 wgpu::ImageDataLayout {
605 offset: 0,
606 bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
607 rows_per_image: std::num::NonZeroU32::new(dimensions.1),
608 },
609 texture_size,
610 );
611
612 let diffuse_texture_view =
613 diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
614
615 self.texture = Some(diffuse_texture_view);
616 }
617}
618
619struct InstanceBufferGroup(SimpleBuffer, SimpleBuffer, SimpleBuffer);