1use derive_more::From;
2use glium::{self, uniform};
3use strum::{EnumCount, EnumIter, FromRepr};
4use vec_map::VecMap;
5
6use math_utils as math;
7
8use crate::{color, mesh, render, shader, vertex, Mesh, Render};
9
10pub const MESH_GRID_DIMS : u16 = 12;
11pub const DEFAULT_PIXELS_PER_UNIT : f32 = 64.0;
13
14pub struct Draw3d {
20 instance_vertices : glium::VertexBuffer <vertex::Vert3dOrientationScaleColor>,
23
24 instanced_aabb_lines : std::ops::Range <u32>,
27 instanced_aabb_triangles : std::ops::Range <u32>,
29 instanced_spheres_raycast : std::ops::Range <u32>,
31 instanced_billboards : VecMap <InstancedBillboard>,
32 instanced_meshes : InstancedMeshes,
33 pub user_buffers : VecMap <glium::VertexBuffer <vertex::Vert3dColor>>,
34 pub user_draw : VecMap <UserDraw>,
35 pub light_directional : math::Unit3 <f32>,
36 pub light_directional_color : color::Rgb <f32>
37}
38
39#[derive(Clone, Debug, Eq, PartialEq)]
40pub struct UserDraw {
41 pub buffer_key : UserBufferKey,
42 pub range : std::ops::Range <u32>,
44 pub primitive_type : glium::index::PrimitiveType,
45 pub shader_program_id : shader::ProgramId,
46 pub draw_pass : DrawPass
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub struct UserBufferKey (pub u32);
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53pub enum DrawPass {
54 Depth,
55 NoDepth
56}
57
58#[derive(Clone, Debug, Eq, PartialEq)]
60pub struct InstancedMesh {
61 pub line_indices_range : std::ops::Range <u32>,
65 pub instances_range : std::ops::Range <u32>,
68 pub shader_program_id : shader::ProgramId,
69 pub draw_pass : DrawPass
70}
71
72pub struct InstancedBillboard {
74 pub texture : glium::Texture2d,
75 pub instances_range : std::ops::Range <u32>
77}
78
79#[derive(Default)]
81pub struct InstancesInit <'a> {
82 pub aabb_lines : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
83 pub aabb_triangles : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
84 pub aabb_lines_and_triangles : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
85 pub spheres_raycast : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
86 pub meshes : VecMap <&'a [vertex::Vert3dOrientationScaleColor]>,
87 pub billboards : VecMap <&'a [vertex::Vert3dOrientationScaleColor]>
88}
89
90#[derive(Clone, Copy, Debug, Eq, PartialEq, From)]
91pub struct MeshKey (pub u32);
92
93#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, EnumCount, EnumIter,
94 FromRepr)]
95#[repr(u16)]
96pub enum MeshId {
97 Grid,
98 Hemisphere,
99 Capsule,
100 Cube,
101 Cylinder,
102 Sphere
103}
104
105struct InstancedMeshes {
110 pub vertices : glium::VertexBuffer <vertex::Vert3dInstanced>,
115 pub line_indices : glium::IndexBuffer <u32>,
121 pub meshes : VecMap <InstancedMesh>,
124 pub capsule_vertex_id_offset : u32,
126 pub hemisphere_vertex_count : u32
127}
128
129struct InstancedMeshInit {
130 pub instanced_vertex_data : Vec <vertex::Vert3dInstanced>,
131 pub instanced_line_index_data : Vec <u32>,
132 pub line_indices_ranges : VecMap <std::ops::Range <u32>>,
133 pub shader_program_ids : VecMap <shader::ProgramId>,
134 pub draw_passes : VecMap <DrawPass>,
135 pub capsule_vertex_id_offset : u32,
136 pub hemisphere_vertex_count : u32
137}
138
139impl Draw3d {
144 pub fn new (glium_display : &glium::Display <glutin::surface::WindowSurface>) -> Self {
145 use color::{Normalize, WithAlphaOpaque};
146 let instanced_aabb_lines = 0..0; let instanced_aabb_triangles = 0..0; let instanced_spheres_raycast = 0..0; let instanced_billboards = VecMap::new();
150 let instanced_meshes = InstancedMeshes::new (glium_display, vec![]);
151 let instance_vertices = glium::VertexBuffer::dynamic (
152 glium_display,
153 &[ vertex::Vert3dOrientationScaleColor {
155 position: [0.0, 0.0, 0.0],
156 orientation: math::Matrix3::identity().into_col_arrays(),
157 scale: [1.0, 1.0, 1.0],
158 color: color::DEBUG_CHARTREUSE.normalize().rgba().into()
159 }
160 ]
161 ).unwrap();
162 let user_buffers = VecMap::new();
163 let user_draw = VecMap::new();
164 let light_directional = -math::Unit3::axis_z();
165 let light_directional_color = color::NOON_SUN.normalize();
166 Draw3d {
167 instance_vertices,
168 instanced_aabb_lines,
169 instanced_aabb_triangles,
170 instanced_spheres_raycast,
171 instanced_billboards,
172 instanced_meshes,
173 user_buffers,
174 user_draw,
175 light_directional,
176 light_directional_color
177 }
178 }
179
180 pub fn draw (
181 render : &Render <render::resource::Default>,
182 glium_frame : &mut glium::Frame
183 ) {
184 use color::{IntoArray, Normalize, WithAlphaOpaque};
185 let draw3d = &render.resource.draw3d;
186 for (_, viewport) in render.viewports.iter() {
188 if let Some (camera3d) = viewport.camera3d() {
189 use glium::Surface;
190 let draw_parameters_viewport = viewport.draw_parameters();
192 let draw_parameters_write_depth = glium::DrawParameters {
194 depth: glium::Depth {
195 test: glium::DepthTest::IfLess,
196 write: true,
197 .. glium::Depth::default()
198 },
199 .. draw_parameters_viewport.clone()
200 };
201 let draw_parameters_polygon_offset = glium::DrawParameters {
203 polygon_offset: glium::draw_parameters::PolygonOffset {
204 factor: 1.0,
205 units: 1.0 / 1024.0,
206 fill: true,
207 .. Default::default()
208 },
209 backface_culling:
210 glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise,
211 .. draw_parameters_write_depth.clone()
212 };
213 let (transform_mat_world_to_view, projection_mat_perspective) =
215 camera3d.view_mats();
216 let projection_mat_perspective_inverse = camera3d.projection().as_matrix()
217 .inverted().into_col_arrays();
218 let light_directional_view = (camera3d.transform_mat_world_to_view()
219 * math::Vector4::from_direction (draw3d.light_directional)
220 ).xyz().into_array();
221 let uniforms = uniform!{
222 uni_transform_mat_view: transform_mat_world_to_view,
223 uni_projection_mat_perspective: projection_mat_perspective,
224 uni_projection_mat_perspective_inverse: projection_mat_perspective_inverse,
225 uni_light_directional_view: light_directional_view,
226 uni_light_directional_color: draw3d.light_directional_color.into_array(),
227 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT,
229 uni_capsule_vertex_id_offset: draw3d.instanced_meshes.capsule_vertex_id_offset,
230 uni_hemisphere_vertex_count: draw3d.instanced_meshes.hemisphere_vertex_count,
231 uni_color: color::BLACK.normalize().rgba().into_array()
232 };
233
234 if !draw3d.instanced_aabb_lines.is_empty() {
236 let instances_range =
237 draw3d.instanced_aabb_lines.start as usize..
238 draw3d.instanced_aabb_lines.end as usize;
239 glium_frame.draw (
240 draw3d.instance_vertices.slice (instances_range).unwrap(),
241 glium::index::IndicesSource::NoIndices {
242 primitives: glium::index::PrimitiveType::Points
243 },
244 &render.resource.shader_programs [
245 shader::ProgramId::WorldSpace3dAabbLines as usize
246 ],
247 &uniforms,
248 &draw_parameters_write_depth
249 ).unwrap();
250 }
251
252 if !draw3d.instanced_aabb_triangles.is_empty() {
254 let instances_range =
255 draw3d.instanced_aabb_triangles.start as usize..
256 draw3d.instanced_aabb_triangles.end as usize;
257 glium_frame.draw (
258 draw3d.instance_vertices.slice (instances_range).unwrap(),
259 glium::index::IndicesSource::NoIndices {
260 primitives: glium::index::PrimitiveType::Points
261 },
262 &render.resource.shader_programs [
263 shader::ProgramId::WorldSpace3dAabbTriangles as usize
264 ],
265 &uniforms,
266 &draw_parameters_polygon_offset
267 ).unwrap();
268 }
269
270 if !draw3d.instanced_spheres_raycast.is_empty() {
272 let instances_range =
273 draw3d.instanced_spheres_raycast.start as usize..
274 draw3d.instanced_spheres_raycast.end as usize;
275 glium_frame.draw (
276 draw3d.instance_vertices.slice (instances_range).unwrap(),
277 glium::index::IndicesSource::NoIndices {
278 primitives: glium::index::PrimitiveType::Points
279 },
280 &render.resource.shader_programs [
281 shader::ProgramId::WorldSpace3dSphere as usize
282 ],
283 &uniforms,
284 &draw_parameters_write_depth
285 ).unwrap();
286 }
287
288 for (_mesh_key, instanced_mesh) in draw3d.instanced_meshes.meshes.iter() {
290 if instanced_mesh.draw_pass != DrawPass::Depth {
291 continue
292 }
293 if !instanced_mesh.instances_range.is_empty() {
294 let (line_indices_range, instances_range) = (
295 instanced_mesh.line_indices_range.start as usize..
296 instanced_mesh.line_indices_range.end as usize,
297 instanced_mesh.instances_range.start as usize..
298 instanced_mesh.instances_range.end as usize
299 );
300 glium_frame.draw (
301 (&draw3d.instanced_meshes.vertices,
302 draw3d.instance_vertices.slice (instances_range).unwrap()
303 .per_instance().unwrap()
304 ),
305 draw3d.instanced_meshes.line_indices.slice (line_indices_range)
306 .unwrap(),
307 &render.resource.shader_programs [instanced_mesh.shader_program_id
308 as usize],
309 &uniforms,
310 &draw_parameters_write_depth
311 ).unwrap();
312 }
313 }
314
315 for user_draw in draw3d.user_draw.values() {
317 if user_draw.draw_pass != DrawPass::Depth {
318 continue
319 }
320 let vertex_buffer = draw3d.user_buffers
321 .get (user_draw.buffer_key.index()).unwrap();
322 let vertex_range =
323 user_draw.range.start as usize..
324 user_draw.range.end as usize;
325 let uniforms = uniform!{
326 uni_transform_mat_view: transform_mat_world_to_view,
327 uni_projection_mat_perspective: projection_mat_perspective,
328 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT,
330 uni_capsule_vertex_id_offset:
331 draw3d.instanced_meshes.capsule_vertex_id_offset,
332 uni_hemisphere_vertex_count:
333 draw3d.instanced_meshes.hemisphere_vertex_count
334 };
335 glium_frame.draw (
336 vertex_buffer.slice (vertex_range).unwrap(),
337 glium::index::NoIndices (user_draw.primitive_type),
338 &render.resource.shader_programs [user_draw.shader_program_id.index()],
339 &uniforms,
340 &draw_parameters_write_depth
341 ).unwrap();
342 }
343
344 for (_mesh_key, instanced_mesh) in draw3d.instanced_meshes.meshes.iter() {
346 if instanced_mesh.draw_pass != DrawPass::NoDepth {
347 continue
348 }
349 if !instanced_mesh.instances_range.is_empty() {
350 let (line_indices_range, instances_range) = (
351 instanced_mesh.line_indices_range.start as usize..
352 instanced_mesh.line_indices_range.end as usize,
353 instanced_mesh.instances_range.start as usize..
354 instanced_mesh.instances_range.end as usize
355 );
356 glium_frame.draw (
357 (&draw3d.instanced_meshes.vertices,
358 draw3d.instance_vertices.slice (instances_range).unwrap()
359 .per_instance().unwrap()
360 ),
361 draw3d.instanced_meshes.line_indices.slice (line_indices_range)
362 .unwrap(),
363 &render.resource.shader_programs [instanced_mesh.shader_program_id
364 as usize],
365 &uniforms,
366 &draw_parameters_viewport
367 ).unwrap();
368 }
369 }
370
371 for user_draw in draw3d.user_draw.values() {
373 if user_draw.draw_pass != DrawPass::NoDepth {
374 continue
375 }
376 let vertex_buffer = draw3d.user_buffers
377 .get (user_draw.buffer_key.index()).unwrap();
378 let vertex_range =
379 user_draw.range.start as usize..
380 user_draw.range.end as usize;
381 glium_frame.draw (
382 vertex_buffer.slice (vertex_range).unwrap(),
383 glium::index::NoIndices (user_draw.primitive_type),
384 &render.resource.shader_programs [user_draw.shader_program_id.index()],
385 &uniforms,
386 &draw_parameters_viewport
387 ).unwrap();
388 }
389
390 for (_, instanced_billboard) in draw3d.instanced_billboards.iter() {
393 let instances_range =
394 instanced_billboard.instances_range.start as usize..
395 instanced_billboard.instances_range.end as usize;
396 let uniforms = uniform!{
397 uni_transform_mat_view: transform_mat_world_to_view,
398 uni_projection_mat_perspective: projection_mat_perspective,
399 uni_sampler2d: instanced_billboard.texture.sampled()
400 .magnify_filter (glium::uniforms::MagnifySamplerFilter::Nearest),
401 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT
403 };
404 glium_frame.draw (
405 draw3d.instance_vertices.slice (instances_range).unwrap(),
406 glium::index::IndicesSource::NoIndices {
407 primitives: glium::index::PrimitiveType::Points
408 },
409 &render.resource.shader_programs [
410 shader::ProgramId::WorldSpace3dSprite as usize
411 ],
412 &uniforms,
413 &draw_parameters_viewport
414 ).unwrap();
415 }
416 }
417 } } #[inline]
421 pub const fn instance_vertices (&self)
422 -> &glium::VertexBuffer <vertex::Vert3dOrientationScaleColor>
423 {
424 &self.instance_vertices
425 }
426
427 #[inline]
428 pub const fn instanced_aabb_lines (&self) -> &std::ops::Range <u32> {
429 &self.instanced_aabb_lines
430 }
431
432 #[inline]
433 pub fn set_instanced_aabb_lines (&mut self, range : std::ops::Range <u32>) {
434 debug_assert!(range.end <= self.instance_vertices.len() as u32);
435 self.instanced_aabb_lines = range;
436 }
437
438 #[inline]
439 pub const fn instanced_aabb_triangles (&self) -> &std::ops::Range <u32> {
440 &self.instanced_aabb_triangles
441 }
442
443 #[inline]
444 pub fn set_instanced_aabb_triangles (&mut self, range : std::ops::Range <u32>) {
445 debug_assert!(range.end <= self.instance_vertices.len() as u32);
446 self.instanced_aabb_triangles = range;
447 }
448
449 #[inline]
450 pub const fn instanced_meshes (&self) -> &VecMap <InstancedMesh> {
451 &self.instanced_meshes.meshes
452 }
453
454 #[inline]
455 pub fn set_instanced_mesh (&mut self,
456 mesh_key : MeshKey, mesh : InstancedMesh
457 ) {
458 let _ = self.instanced_meshes.meshes.insert (mesh_key.index(), mesh);
459 }
460
461 pub fn rebuild_instanced_meshes (&mut self,
465 glium_display : &glium::Display <glutin::surface::WindowSurface>,
466 user_meshes : Vec <(MeshKey, Mesh, DrawPass)>
467 ) {
468 self.instanced_meshes = InstancedMeshes::new (glium_display, user_meshes);
469 }
470
471 pub fn instance_vertices_set (&mut self,
475 glium_display : &glium::Display <glutin::surface::WindowSurface>,
476 instances_init : InstancesInit
477 ) {
478 let mut instance_vertices =
479 Vec::with_capacity (instances_init.instance_count());
480
481 self.instanced_aabb_lines = 0..0;
482 self.instanced_aabb_triangles = 0..0;
483 for mesh in self.instanced_meshes.meshes.values_mut() {
484 mesh.instances_range = 0..0;
485 }
486 if let Some (instances) = instances_init.aabb_lines {
490 let start = instance_vertices.len() as u32;
492 instance_vertices.extend_from_slice (instances);
493 let end = instance_vertices.len() as u32;
494 self.instanced_aabb_lines = start..end;
495 }
496 if let Some (instances) = instances_init.aabb_lines_and_triangles {
497 let start = instance_vertices.len() as u32;
499 instance_vertices.extend_from_slice (instances);
500 let end = instance_vertices.len() as u32;
501 if self.instanced_aabb_lines.end != 0 {
502 debug_assert!(instances_init.aabb_lines.is_none());
503 self.instanced_aabb_lines.start = start;
504 }
505 self.instanced_aabb_lines.end = end;
506 self.instanced_aabb_triangles = start..end;
507 }
508 if let Some (instances) = instances_init.aabb_triangles {
509 let start = instance_vertices.len() as u32;
511 instance_vertices.extend_from_slice (instances);
512 let end = instance_vertices.len() as u32;
513 if self.instanced_aabb_triangles.end == 0 {
514 debug_assert!(instances_init.aabb_lines_and_triangles.is_none());
515 self.instanced_aabb_triangles.start = start;
516 }
517 self.instanced_aabb_triangles.end = end;
518 }
519
520 if let Some (instances) = instances_init.spheres_raycast {
522 let start = instance_vertices.len() as u32;
523 instance_vertices.extend_from_slice (instances);
524 let end = instance_vertices.len() as u32;
525 self.instanced_spheres_raycast = start..end;
526 }
527
528 for (mesh_key, instances) in instances_init.meshes.into_iter() {
530 let start = instance_vertices.len() as u32;
531 instance_vertices.extend_from_slice (instances);
532 let end = instance_vertices.len() as u32;
533 self.instanced_meshes.meshes[mesh_key].instances_range = start..end;
534 }
535
536 for (billboard_key, instances) in instances_init.billboards.into_iter() {
538 let start = instance_vertices.len() as u32;
539 instance_vertices.extend_from_slice (instances);
540 let end = instance_vertices.len() as u32;
541 self.instanced_billboards[billboard_key].instances_range = start..end;
542 }
543
544 self.instance_vertices = glium::VertexBuffer::dynamic (
546 glium_display, instance_vertices.as_slice()
547 ).unwrap();
548 }
549
550 #[inline]
551 pub fn instance_vertices_aabb_lines_write (&self,
552 vertex_data : &[vertex::Vert3dOrientationScaleColor]
553 ) {
554 let range =
555 self.instanced_aabb_lines.start as usize..
556 self.instanced_aabb_lines.end as usize;
557 self.instance_vertices.slice (range).unwrap().write (vertex_data);
558 }
559
560 #[inline]
561 pub fn instance_vertices_aabb_triangles_write (&self,
562 vertex_data : &[vertex::Vert3dOrientationScaleColor]
563 ) {
564 let range =
565 self.instanced_aabb_triangles.start as usize..
566 self.instanced_aabb_triangles.end as usize;
567 self.instance_vertices.slice (range).unwrap().write (vertex_data);
568 }
569
570 #[inline]
571 pub fn instance_vertices_spheres_raycast_write (&self,
572 vertex_data : &[vertex::Vert3dOrientationScaleColor]
573 ) {
574 let range =
575 self.instanced_spheres_raycast.start as usize..
576 self.instanced_spheres_raycast.end as usize;
577 self.instance_vertices.slice (range).unwrap().write (vertex_data);
578 }
579
580 #[inline]
581 pub fn instance_vertices_billboard_write (&self,
582 billboard_key : usize,
583 vertex_data : &[vertex::Vert3dOrientationScaleColor]
584 ) {
585 let range = {
586 let range = self.instanced_billboards[billboard_key].instances_range.clone();
587 range.start as usize..range.end as usize
588 };
589 self.instance_vertices.slice (range).unwrap().write (vertex_data);
590 }
591
592 #[inline]
593 pub fn instance_vertices_mesh_write (&self,
594 mesh_key : usize,
595 vertex_data : &[vertex::Vert3dOrientationScaleColor]
596 ) {
597 let range = {
598 let range = self.instanced_meshes.meshes[mesh_key].instances_range.clone();
599 range.start as usize..range.end as usize
600 };
601 self.instance_vertices.slice (range).unwrap().write (vertex_data);
602 }
603
604 pub fn tile_billboard_create (&mut self,
609 glium_display : &glium::Display <glutin::surface::WindowSurface>,
610 tileset_texture : &glium::Texture2d,
611 billboard_key : usize,
612 instances_range : std::ops::Range <u32>,
613 string : &str
614 ) {
615 use glium::Surface;
616 debug_assert_eq!(0, tileset_texture.width() %16);
617 debug_assert_eq!(0, tileset_texture.height()%16);
618 let tile_width = tileset_texture.width() / 16;
619 let tile_height = tileset_texture.height() / 16;
620 let texture = glium::Texture2d::empty_with_mipmaps (
621 glium_display, glium::texture::MipmapsOption::NoMipmap,
622 tile_width * string.len() as u32, tile_height
623 ).unwrap();
624 { let source = tileset_texture.as_surface();
626 let mut target = texture.as_surface();
627 target.clear_color (1.0, 0.0, 1.0, 1.0);
628 for (i,ch) in string.chars().enumerate() {
629 let tile = ch as u32;
630 let source_rect = glium::Rect {
632 left: tile_width * (tile % 16),
633 bottom: tile_height * (15 - tile / 16),
634 width: tile_width,
635 height: tile_height
636 };
637 #[expect(clippy::identity_op)]
638 let target_rect = glium::BlitTarget {
639 left: 0 + i as u32 * tile_width,
640 bottom: 0,
641 width: tile_width as i32,
642 height: tile_height as i32
643 };
644 target.blit_from_simple_framebuffer (
645 &source, &source_rect, &target_rect,
646 glium::uniforms::MagnifySamplerFilter::Linear);
647 }
648 }
649 let instanced_billboard = InstancedBillboard { texture, instances_range };
650 assert!(self.instanced_billboards.insert (
651 billboard_key, instanced_billboard
652 ).is_none());
653 }
654}
655
656impl InstancesInit <'_> {
657 pub fn instance_count (&self) -> usize {
658 let mut count = 0;
659 count += self.aabb_lines.map_or(0, <[_]>::len);
660 count += self.aabb_triangles.map_or(0, <[_]>::len);
661 for (_, mesh_data) in self.meshes.iter() {
662 count += mesh_data.len();
663 }
664 for (_, billboard_data) in self.billboards.iter() {
665 count += billboard_data.len();
666 }
667 count
668 }
669}
670
671impl InstancedMeshes {
672 fn new (
673 glium_display : &glium::Display <glutin::surface::WindowSurface>,
674 user_meshes : Vec <(MeshKey, Mesh, DrawPass)>
675 ) -> Self {
676 let InstancedMeshInit {
677 instanced_vertex_data,
678 instanced_line_index_data,
679 line_indices_ranges,
680 shader_program_ids,
681 draw_passes,
682 capsule_vertex_id_offset,
683 hemisphere_vertex_count
684 } = InstancedMeshInit::new (user_meshes);
685 let vertices = glium::VertexBuffer::dynamic (
686 glium_display, instanced_vertex_data.as_slice()
687 ).unwrap();
688 let line_indices = glium::IndexBuffer::dynamic (
689 glium_display, glium::index::PrimitiveType::LinesList,
690 instanced_line_index_data.as_slice()
691 ).unwrap();
692 let meshes = {
693 let mut v = VecMap::new();
694 for (mesh_key, line_indices_range) in line_indices_ranges.into_iter() {
695 let instanced_mesh = InstancedMesh {
696 line_indices_range,
697 instances_range: 0..0, shader_program_id: shader_program_ids[mesh_key],
699 draw_pass: draw_passes[mesh_key]
700 };
701 assert!(v.insert (mesh_key, instanced_mesh).is_none());
702 }
703 v
704 };
705 InstancedMeshes {
706 vertices, line_indices, meshes, capsule_vertex_id_offset,
707 hemisphere_vertex_count
708 }
709 }
710}
711
712impl InstancedMeshInit {
713 fn new (user_meshes : Vec <(MeshKey, Mesh, DrawPass)>) -> Self {
714 const GRID_DIMS : u16 = MESH_GRID_DIMS;
715 const HEMISPHERE_LATITUDE_DIVS : u16 = 6;
716 const SPHERE_LATITUDE_DIVS : u16 = 2 * HEMISPHERE_LATITUDE_DIVS;
717 const LONGITUDE_DIVS : u16 = 24;
718 const CYLINDER_DIVS : u16 = LONGITUDE_DIVS;
719 let mut instanced_vertex_data = Vec::new();
720 let mut instanced_line_index_data = Vec::new();
721 let mut index_offset = 0;
723 let mut index_range_start = 0;
725
726 let mut line_indices_ranges = VecMap::with_capacity (MeshId::COUNT);
727 let mut shader_program_ids = VecMap::with_capacity (MeshId::COUNT);
728 let mut draw_passes = VecMap::with_capacity (MeshId::COUNT);
729
730 let mesh::Lines3d {
732 vertices: mut grid_vertex_data, indices: mut grid_index_data
733 } = mesh::Lines3d::grid (index_offset, GRID_DIMS);
734 assert!(line_indices_ranges.insert (
735 MeshId::Grid as usize,
736 index_range_start..index_range_start + grid_index_data.len() as u32
737 ).is_none());
738 assert!(shader_program_ids.insert (
739 MeshId::Grid as usize,
740 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
741 ).is_none());
742 assert!(draw_passes.insert (MeshId::Grid as usize, DrawPass::Depth).is_none());
743 instanced_vertex_data.append (&mut grid_vertex_data);
744 instanced_line_index_data.append (&mut grid_index_data);
745 index_offset = instanced_vertex_data.len() as u32;
746 index_range_start = instanced_line_index_data.len() as u32;
747
748 let capsule_vertex_id_offset = index_offset; let mesh::Lines3d {
752 vertices: mut capsule_vertex_data,
753 indices: mut capsule_index_data
754 } = mesh::Lines3d::capsule (index_offset, HEMISPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
755 let capsule_line_indices_range =
756 index_range_start..index_range_start + capsule_index_data.len() as u32;
757 assert!(line_indices_ranges.insert (
758 MeshId::Capsule as usize, capsule_line_indices_range.clone()
759 ).is_none());
760 assert!(shader_program_ids.insert (
761 MeshId::Capsule as usize,
762 shader::ProgramId::ModelSpace3dInstancedCapsule
763 ).is_none());
764 assert!(draw_passes.insert (MeshId::Capsule as usize, DrawPass::Depth).is_none());
765 instanced_vertex_data.append (&mut capsule_vertex_data);
766 instanced_line_index_data.append (&mut capsule_index_data);
767
768 index_offset = instanced_vertex_data.len() as u32;
769 index_range_start = instanced_line_index_data.len() as u32;
770
771 let (hemisphere_vertex_count, hemisphere_index_count) =
774 mesh::hemisphere::lines3d_vertex_index_counts (
775 HEMISPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
776 assert!(line_indices_ranges.insert (
777 MeshId::Hemisphere as usize,
778 capsule_line_indices_range.start..
779 capsule_line_indices_range.start + hemisphere_index_count
780 ).is_none());
781 assert!(shader_program_ids.insert (
782 MeshId::Hemisphere as usize,
783 shader::ProgramId::ModelSpace3dInstancedScaleColor
784 ).is_none());
785 assert!(draw_passes.insert (MeshId::Hemisphere as usize, DrawPass::Depth)
786 .is_none());
787
788 let (_, sphere_index_count) = mesh::sphere::lines3d_vertex_index_counts (
791 SPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
792 assert!(line_indices_ranges.insert (
793 MeshId::Sphere as usize,
794 capsule_line_indices_range.start..
795 capsule_line_indices_range.start + sphere_index_count
796 ).is_none());
797 assert!(shader_program_ids.insert (
798 MeshId::Sphere as usize,
799 shader::ProgramId::ModelSpace3dInstancedScaleColor
800 ).is_none());
801 assert!(draw_passes.insert (MeshId::Sphere as usize, DrawPass::Depth)
802 .is_none());
803
804 let mesh::Lines3d {
806 vertices: mut cylinder_vertex_data, indices: mut cylinder_index_data
807 } = mesh::Lines3d::cylinder (index_offset, CYLINDER_DIVS);
808 assert!(line_indices_ranges.insert (
809 MeshId::Cylinder as usize,
810 index_range_start..index_range_start + cylinder_index_data.len() as u32
811 ).is_none());
812 assert!(shader_program_ids.insert (
813 MeshId::Cylinder as usize,
814 shader::ProgramId::ModelSpace3dInstancedScaleColor
815 ).is_none());
816 assert!(draw_passes.insert (MeshId::Cylinder as usize, DrawPass::Depth)
817 .is_none());
818 instanced_vertex_data.append (&mut cylinder_vertex_data);
819 instanced_line_index_data.append (&mut cylinder_index_data);
820
821 index_offset = instanced_vertex_data.len() as u32;
822 index_range_start = instanced_line_index_data.len() as u32;
823
824 let mesh::Lines3d {
826 vertices: mut cube_vertex_data, indices: mut cube_index_data
827 } = mesh::Lines3d::cube (index_offset);
828 assert!(line_indices_ranges.insert (
829 MeshId::Cube as usize,
830 index_range_start..index_range_start + cube_index_data.len() as u32
831 ).is_none());
832 assert!(shader_program_ids.insert (
833 MeshId::Cube as usize,
834 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
835 ).is_none());
836 assert!(draw_passes.insert (MeshId::Cube as usize, DrawPass::Depth).is_none());
837 instanced_vertex_data.append (&mut cube_vertex_data);
838 instanced_line_index_data.append (&mut cube_index_data);
839
840 let num_user_meshes = user_meshes.len();
847 for (mesh_key, mut mesh, draw_pass) in user_meshes {
848 debug_assert!(mesh_key.index() >= MeshId::COUNT);
849 index_offset = instanced_vertex_data.len() as u32;
850 index_range_start = instanced_line_index_data.len() as u32;
851 let mut insert_mesh = |vertices : &mut Vec <_>, indices : &mut Vec <u32>| {
852 indices.iter_mut().for_each (|ix| *ix += index_offset);
853 assert!(line_indices_ranges.insert (
854 mesh_key.index(),
855 index_range_start..index_range_start + indices.len() as u32
856 ).is_none());
857 assert!(shader_program_ids.insert (
858 mesh_key.index(),
859 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
860 ).is_none());
861 assert!(draw_passes.insert (mesh_key.index(), draw_pass).is_none());
862 instanced_vertex_data.append (vertices);
863 instanced_line_index_data.append (indices);
864 };
865 match mesh {
866 Mesh::Points3d (mesh::Points3d { ref mut vertices, ref mut indices }) |
867 Mesh::Lines3d (mesh::Lines3d { ref mut vertices, ref mut indices }) |
868 Mesh::Triangles3d (mesh::Triangles3d { ref mut vertices, ref mut indices }) =>
869 insert_mesh (vertices, indices)
870 }
871 }
872
873 debug_assert_eq!(line_indices_ranges.len(), MeshId::COUNT + num_user_meshes);
874 debug_assert_eq!(shader_program_ids.len(), MeshId::COUNT + num_user_meshes);
875
876 InstancedMeshInit {
877 instanced_vertex_data,
878 instanced_line_index_data,
879 line_indices_ranges,
880 shader_program_ids,
881 draw_passes,
882 capsule_vertex_id_offset,
883 hemisphere_vertex_count
884 }
885 }
886}
887
888impl MeshKey {
889 pub const fn index (self) -> usize {
890 self.0 as usize
891 }
892}
893
894impl UserBufferKey {
895 pub const fn index (self) -> usize {
896 self.0 as usize
897 }
898}