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_billboards : VecMap <InstancedBillboard>,
30 instanced_meshes : InstancedMeshes,
31 pub user_buffers : VecMap <glium::VertexBuffer <vertex::Vert3dColor>>,
32 pub user_draw : VecMap <UserDraw>,
33}
34
35#[derive(Clone, Debug, Eq, PartialEq)]
36pub struct UserDraw {
37 pub buffer_key : UserBufferKey,
38 pub range : std::ops::Range <u32>,
40 pub primitive_type : glium::index::PrimitiveType,
41 pub shader_program_id : shader::ProgramId,
42 pub draw_pass : DrawPass
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub struct UserBufferKey (pub u32);
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq)]
49pub enum DrawPass {
50 Depth,
51 NoDepth
52}
53
54#[derive(Clone, Debug, Eq, PartialEq)]
56pub struct InstancedMesh {
57 pub line_indices_range : std::ops::Range <u32>,
61 pub instances_range : std::ops::Range <u32>,
64 pub shader_program_id : shader::ProgramId,
65 pub draw_pass : DrawPass
66}
67
68pub struct InstancedBillboard {
70 pub texture : glium::Texture2d,
71 pub instances_range : std::ops::Range <u32>
73}
74
75#[derive(Default)]
77pub struct InstancesInit <'a> {
78 pub aabb_lines : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
79 pub aabb_triangles : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
80 pub aabb_lines_and_triangles : Option <&'a [vertex::Vert3dOrientationScaleColor]>,
81 pub meshes : VecMap <&'a [vertex::Vert3dOrientationScaleColor]>,
82 pub billboards : VecMap <&'a [vertex::Vert3dOrientationScaleColor]>
83}
84
85#[derive(Clone, Copy, Debug, Eq, PartialEq, From)]
86pub struct MeshKey (pub u32);
87
88#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, EnumCount, EnumIter,
89 FromRepr)]
90#[repr(u16)]
91pub enum MeshId {
92 Grid,
93 Hemisphere,
94 Capsule,
95 Cube,
96 Cylinder,
97 Sphere
98}
99
100struct InstancedMeshes {
105 pub vertices : glium::VertexBuffer <vertex::Vert3dInstanced>,
110 pub line_indices : glium::IndexBuffer <u32>,
116 pub meshes : VecMap <InstancedMesh>,
119 pub capsule_vertex_id_offset : u32,
121 pub hemisphere_vertex_count : u32
122}
123
124struct InstancedMeshInit {
125 pub instanced_vertex_data : Vec <vertex::Vert3dInstanced>,
126 pub instanced_line_index_data : Vec <u32>,
127 pub line_indices_ranges : VecMap <std::ops::Range <u32>>,
128 pub shader_program_ids : VecMap <shader::ProgramId>,
129 pub draw_passes : VecMap <DrawPass>,
130 pub capsule_vertex_id_offset : u32,
131 pub hemisphere_vertex_count : u32
132}
133
134impl Draw3d {
139 pub fn new (glium_display : &glium::Display <glutin::surface::WindowSurface>) -> Self {
140 let instanced_aabb_lines = 0..0; let instanced_aabb_triangles = 0..0; let instanced_billboards = VecMap::new();
143 let instanced_meshes = InstancedMeshes::new (glium_display, vec![]);
144 let instance_vertices = glium::VertexBuffer::dynamic (
145 glium_display,
146 &[ vertex::Vert3dOrientationScaleColor {
148 position: [0.0, 0.0, 0.0],
149 orientation: math::Matrix3::identity().into_col_arrays(),
150 scale: [1.0, 1.0, 1.0],
151 color: color::rgba_u8_to_rgba_f32 (color::DEBUG_CHARTREUSE)
152 }
153 ]
154 ).unwrap();
155 let user_buffers = VecMap::new();
156 let user_draw = VecMap::new();
157 Draw3d {
158 instance_vertices,
159 instanced_aabb_lines,
160 instanced_aabb_triangles,
161 instanced_billboards,
162 instanced_meshes,
163 user_buffers,
164 user_draw
165 }
166 }
167
168 pub fn draw (
169 render : &Render <render::resource::Default>,
170 glium_frame : &mut glium::Frame
171 ) {
172 let draw3d = &render.resource.draw3d;
173 for (_, viewport) in render.viewports.iter() {
175 if let Some (camera3d) = viewport.camera3d() {
176 use glium::Surface;
177 let draw_parameters_viewport = viewport.draw_parameters();
179 let draw_parameters_write_depth = glium::DrawParameters {
181 depth: glium::Depth {
182 test: glium::DepthTest::IfLess,
183 write: true,
184 .. glium::Depth::default()
185 },
186 .. draw_parameters_viewport.clone()
187 };
188 let draw_parameters_polygon_offset = glium::DrawParameters {
190 polygon_offset: glium::draw_parameters::PolygonOffset {
191 factor: 1.0,
192 units: 1.0 / 1024.0,
193 fill: true,
194 .. Default::default()
195 },
196 backface_culling:
197 glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise,
198 .. draw_parameters_write_depth.clone()
199 };
200 let (transform_mat_world_to_view, projection_mat_perspective) =
202 camera3d.view_mats();
203 let uniforms = uniform!{
204 uni_transform_mat_view: transform_mat_world_to_view,
205 uni_projection_mat_perspective: projection_mat_perspective,
206 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT,
208 uni_capsule_vertex_id_offset:
209 draw3d.instanced_meshes.capsule_vertex_id_offset,
210 uni_hemisphere_vertex_count:
211 draw3d.instanced_meshes.hemisphere_vertex_count,
212 uni_color: color::rgba_u8_to_rgba_f32 (color::BLACK)
213 };
214
215 if !draw3d.instanced_aabb_lines.is_empty() {
217 let instances_range =
218 draw3d.instanced_aabb_lines.start as usize..
219 draw3d.instanced_aabb_lines.end as usize;
220 glium_frame.draw (
221 draw3d.instance_vertices.slice (instances_range).unwrap(),
222 glium::index::IndicesSource::NoIndices {
223 primitives: glium::index::PrimitiveType::Points
224 },
225 &render.resource.shader_programs [
226 shader::ProgramId::WorldSpace3dAabbLines as usize
227 ],
228 &uniforms,
229 &draw_parameters_write_depth
230 ).unwrap();
231 }
232
233 if !draw3d.instanced_aabb_triangles.is_empty() {
235 let instances_range =
236 draw3d.instanced_aabb_triangles.start as usize..
237 draw3d.instanced_aabb_triangles.end as usize;
238 glium_frame.draw (
239 draw3d.instance_vertices.slice (instances_range).unwrap(),
240 glium::index::IndicesSource::NoIndices {
241 primitives: glium::index::PrimitiveType::Points
242 },
243 &render.resource.shader_programs [
244 shader::ProgramId::WorldSpace3dAabbTriangles as usize
245 ],
246 &uniforms,
247 &draw_parameters_polygon_offset
248 ).unwrap();
249 }
250
251 for (_mesh_key, instanced_mesh) in draw3d.instanced_meshes.meshes.iter() {
253 if instanced_mesh.draw_pass != DrawPass::Depth {
254 continue
255 }
256 if !instanced_mesh.instances_range.is_empty() {
257 let (line_indices_range, instances_range) = (
258 instanced_mesh.line_indices_range.start as usize..
259 instanced_mesh.line_indices_range.end as usize,
260 instanced_mesh.instances_range.start as usize..
261 instanced_mesh.instances_range.end as usize
262 );
263 glium_frame.draw (
264 (&draw3d.instanced_meshes.vertices,
265 draw3d.instance_vertices.slice (instances_range).unwrap()
266 .per_instance().unwrap()
267 ),
268 draw3d.instanced_meshes.line_indices.slice (line_indices_range)
269 .unwrap(),
270 &render.resource.shader_programs [instanced_mesh.shader_program_id
271 as usize],
272 &uniforms,
273 &draw_parameters_write_depth
274 ).unwrap();
275 }
276 }
277
278 for user_draw in draw3d.user_draw.values() {
280 if user_draw.draw_pass != DrawPass::Depth {
281 continue
282 }
283 let vertex_buffer = draw3d.user_buffers
284 .get (user_draw.buffer_key.index()).unwrap();
285 let vertex_range =
286 user_draw.range.start as usize..
287 user_draw.range.end as usize;
288 let uniforms = uniform!{
289 uni_transform_mat_view: transform_mat_world_to_view,
290 uni_projection_mat_perspective: projection_mat_perspective,
291 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT,
293 uni_capsule_vertex_id_offset:
294 draw3d.instanced_meshes.capsule_vertex_id_offset,
295 uni_hemisphere_vertex_count:
296 draw3d.instanced_meshes.hemisphere_vertex_count
297 };
298 glium_frame.draw (
299 vertex_buffer.slice (vertex_range).unwrap(),
300 glium::index::NoIndices (user_draw.primitive_type),
301 &render.resource.shader_programs [user_draw.shader_program_id.index()],
302 &uniforms,
303 &draw_parameters_write_depth
304 ).unwrap();
305 }
306
307 for (_mesh_key, instanced_mesh) in draw3d.instanced_meshes.meshes.iter() {
309 if instanced_mesh.draw_pass != DrawPass::NoDepth {
310 continue
311 }
312 if !instanced_mesh.instances_range.is_empty() {
313 let (line_indices_range, instances_range) = (
314 instanced_mesh.line_indices_range.start as usize..
315 instanced_mesh.line_indices_range.end as usize,
316 instanced_mesh.instances_range.start as usize..
317 instanced_mesh.instances_range.end as usize
318 );
319 glium_frame.draw (
320 (&draw3d.instanced_meshes.vertices,
321 draw3d.instance_vertices.slice (instances_range).unwrap()
322 .per_instance().unwrap()
323 ),
324 draw3d.instanced_meshes.line_indices.slice (line_indices_range)
325 .unwrap(),
326 &render.resource.shader_programs [instanced_mesh.shader_program_id
327 as usize],
328 &uniforms,
329 &draw_parameters_viewport
330 ).unwrap();
331 }
332 }
333
334 for user_draw in draw3d.user_draw.values() {
336 if user_draw.draw_pass != DrawPass::NoDepth {
337 continue
338 }
339 let vertex_buffer = draw3d.user_buffers
340 .get (user_draw.buffer_key.index()).unwrap();
341 let vertex_range =
342 user_draw.range.start as usize..
343 user_draw.range.end as usize;
344 glium_frame.draw (
345 vertex_buffer.slice (vertex_range).unwrap(),
346 glium::index::NoIndices (user_draw.primitive_type),
347 &render.resource.shader_programs [user_draw.shader_program_id.index()],
348 &uniforms,
349 &draw_parameters_viewport
350 ).unwrap();
351 }
352
353 for (_, instanced_billboard) in draw3d.instanced_billboards.iter() {
356 let instances_range =
357 instanced_billboard.instances_range.start as usize..
358 instanced_billboard.instances_range.end as usize;
359 let uniforms = uniform!{
360 uni_transform_mat_view: transform_mat_world_to_view,
361 uni_projection_mat_perspective: projection_mat_perspective,
362 uni_sampler2d: instanced_billboard.texture.sampled()
363 .magnify_filter (glium::uniforms::MagnifySamplerFilter::Nearest),
364 uni_pixels_per_unit: DEFAULT_PIXELS_PER_UNIT
366 };
367 glium_frame.draw (
368 draw3d.instance_vertices.slice (instances_range).unwrap(),
369 glium::index::IndicesSource::NoIndices {
370 primitives: glium::index::PrimitiveType::Points
371 },
372 &render.resource.shader_programs [
373 shader::ProgramId::WorldSpace3dSprite as usize
374 ],
375 &uniforms,
376 &draw_parameters_viewport
377 ).unwrap();
378 }
379 }
380 } } #[inline]
384 pub const fn instance_vertices (&self)
385 -> &glium::VertexBuffer <vertex::Vert3dOrientationScaleColor>
386 {
387 &self.instance_vertices
388 }
389
390 #[inline]
391 pub const fn instanced_aabb_lines (&self) -> &std::ops::Range <u32> {
392 &self.instanced_aabb_lines
393 }
394
395 #[inline]
396 pub fn set_instanced_aabb_lines (&mut self, range : std::ops::Range <u32>) {
397 debug_assert!(range.end <= self.instance_vertices.len() as u32);
398 self.instanced_aabb_lines = range;
399 }
400
401 #[inline]
402 pub const fn instanced_aabb_triangles (&self) -> &std::ops::Range <u32> {
403 &self.instanced_aabb_triangles
404 }
405
406 #[inline]
407 pub fn set_instanced_aabb_triangles (&mut self, range : std::ops::Range <u32>) {
408 debug_assert!(range.end <= self.instance_vertices.len() as u32);
409 self.instanced_aabb_triangles = range;
410 }
411
412 #[inline]
413 pub const fn instanced_meshes (&self) -> &VecMap <InstancedMesh> {
414 &self.instanced_meshes.meshes
415 }
416
417 #[inline]
418 pub fn set_instanced_mesh (&mut self,
419 mesh_key : MeshKey, mesh : InstancedMesh
420 ) {
421 let _ = self.instanced_meshes.meshes.insert (mesh_key.index(), mesh);
422 }
423
424 pub fn rebuild_instanced_meshes (&mut self,
428 glium_display : &glium::Display <glutin::surface::WindowSurface>,
429 user_meshes : Vec <(MeshKey, Mesh, DrawPass)>
430 ) {
431 self.instanced_meshes = InstancedMeshes::new (glium_display, user_meshes);
432 }
433
434 pub fn instance_vertices_set (&mut self,
438 glium_display : &glium::Display <glutin::surface::WindowSurface>,
439 instances_init : InstancesInit
440 ) {
441 let mut instance_vertices =
442 Vec::with_capacity (instances_init.instance_count());
443
444 self.instanced_aabb_lines = 0..0;
445 self.instanced_aabb_triangles = 0..0;
446 for mesh in self.instanced_meshes.meshes.values_mut() {
447 mesh.instances_range = 0..0;
448 }
449 if let Some (instances) = instances_init.aabb_lines {
453 let start = instance_vertices.len() as u32;
455 instance_vertices.extend_from_slice (instances);
456 let end = instance_vertices.len() as u32;
457 self.instanced_aabb_lines = start..end;
458 }
459 if let Some (instances) = instances_init.aabb_lines_and_triangles {
460 let start = instance_vertices.len() as u32;
462 instance_vertices.extend_from_slice (instances);
463 let end = instance_vertices.len() as u32;
464 if self.instanced_aabb_lines.end != 0 {
465 debug_assert!(instances_init.aabb_lines.is_none());
466 self.instanced_aabb_lines.start = start;
467 }
468 self.instanced_aabb_lines.end = end;
469 self.instanced_aabb_triangles = start..end;
470 }
471 if let Some (instances) = instances_init.aabb_triangles {
472 let start = instance_vertices.len() as u32;
474 instance_vertices.extend_from_slice (instances);
475 let end = instance_vertices.len() as u32;
476 if self.instanced_aabb_triangles.end == 0 {
477 debug_assert!(instances_init.aabb_lines_and_triangles.is_none());
478 self.instanced_aabb_triangles.start = start;
479 }
480 self.instanced_aabb_triangles.end = end;
481 }
482
483 for (mesh_key, instances) in instances_init.meshes.into_iter() {
485 let start = instance_vertices.len() as u32;
486 instance_vertices.extend_from_slice (instances);
487 let end = instance_vertices.len() as u32;
488 self.instanced_meshes.meshes[mesh_key].instances_range = start..end;
489 }
490
491 for (billboard_key, instances) in instances_init.billboards.into_iter() {
493 let start = instance_vertices.len() as u32;
494 instance_vertices.extend_from_slice (instances);
495 let end = instance_vertices.len() as u32;
496 self.instanced_billboards[billboard_key].instances_range = start..end;
497 }
498
499 self.instance_vertices = glium::VertexBuffer::dynamic (
501 glium_display, instance_vertices.as_slice()
502 ).unwrap();
503 }
504
505 #[inline]
506 pub fn instance_vertices_aabb_lines_write (&self,
507 vertex_data : &[vertex::Vert3dOrientationScaleColor]
508 ) {
509 let range =
510 self.instanced_aabb_lines.start as usize..
511 self.instanced_aabb_lines.end as usize;
512 self.instance_vertices.slice (range).unwrap().write (vertex_data);
513 }
514
515 #[inline]
516 pub fn instance_vertices_aabb_triangles_write (&self,
517 vertex_data : &[vertex::Vert3dOrientationScaleColor]
518 ) {
519 let range =
520 self.instanced_aabb_triangles.start as usize..
521 self.instanced_aabb_triangles.end as usize;
522 self.instance_vertices.slice (range).unwrap().write (vertex_data);
523 }
524
525 #[inline]
526 pub fn instance_vertices_billboard_write (&self,
527 billboard_key : usize,
528 vertex_data : &[vertex::Vert3dOrientationScaleColor]
529 ) {
530 let range = {
531 let range = self.instanced_billboards[billboard_key].instances_range.clone();
532 range.start as usize..range.end as usize
533 };
534 self.instance_vertices.slice (range).unwrap().write (vertex_data);
535 }
536
537 #[inline]
538 pub fn instance_vertices_mesh_write (&self,
539 mesh_key : usize,
540 vertex_data : &[vertex::Vert3dOrientationScaleColor]
541 ) {
542 let range = {
543 let range = self.instanced_meshes.meshes[mesh_key].instances_range.clone();
544 range.start as usize..range.end as usize
545 };
546 self.instance_vertices.slice (range).unwrap().write (vertex_data);
547 }
548
549 pub fn tile_billboard_create (&mut self,
554 glium_display : &glium::Display <glutin::surface::WindowSurface>,
555 tileset_texture : &glium::Texture2d,
556 billboard_key : usize,
557 instances_range : std::ops::Range <u32>,
558 string : &str
559 ) {
560 use glium::Surface;
561 debug_assert_eq!(0, tileset_texture.width() %16);
562 debug_assert_eq!(0, tileset_texture.height()%16);
563 let tile_width = tileset_texture.width() / 16;
564 let tile_height = tileset_texture.height() / 16;
565 let texture = glium::Texture2d::empty_with_mipmaps (
566 glium_display, glium::texture::MipmapsOption::NoMipmap,
567 tile_width * string.len() as u32, tile_height
568 ).unwrap();
569 { let source = tileset_texture.as_surface();
571 let mut target = texture.as_surface();
572 target.clear_color (1.0, 0.0, 1.0, 1.0);
573 for (i,ch) in string.chars().enumerate() {
574 let tile = ch as u32;
575 let source_rect = glium::Rect {
577 left: tile_width * (tile % 16),
578 bottom: tile_height * (15 - tile / 16),
579 width: tile_width,
580 height: tile_height
581 };
582 #[expect(clippy::identity_op)]
583 let target_rect = glium::BlitTarget {
584 left: 0 + i as u32 * tile_width,
585 bottom: 0,
586 width: tile_width as i32,
587 height: tile_height as i32
588 };
589 target.blit_from_simple_framebuffer (
590 &source, &source_rect, &target_rect,
591 glium::uniforms::MagnifySamplerFilter::Linear);
592 }
593 }
594 let instanced_billboard = InstancedBillboard { texture, instances_range };
595 assert!(self.instanced_billboards.insert (
596 billboard_key, instanced_billboard
597 ).is_none());
598 }
599}
600
601impl InstancesInit <'_> {
602 pub fn instance_count (&self) -> usize {
603 let mut count = 0;
604 count += self.aabb_lines.map_or(0, <[_]>::len);
605 count += self.aabb_triangles.map_or(0, <[_]>::len);
606 for (_, mesh_data) in self.meshes.iter() {
607 count += mesh_data.len();
608 }
609 for (_, billboard_data) in self.billboards.iter() {
610 count += billboard_data.len();
611 }
612 count
613 }
614}
615
616impl InstancedMeshes {
617 fn new (
618 glium_display : &glium::Display <glutin::surface::WindowSurface>,
619 user_meshes : Vec <(MeshKey, Mesh, DrawPass)>
620 ) -> Self {
621 let InstancedMeshInit {
622 instanced_vertex_data,
623 instanced_line_index_data,
624 line_indices_ranges,
625 shader_program_ids,
626 draw_passes,
627 capsule_vertex_id_offset,
628 hemisphere_vertex_count
629 } = InstancedMeshInit::new (user_meshes);
630 let vertices = glium::VertexBuffer::dynamic (
631 glium_display, instanced_vertex_data.as_slice()
632 ).unwrap();
633 let line_indices = glium::IndexBuffer::dynamic (
634 glium_display, glium::index::PrimitiveType::LinesList,
635 instanced_line_index_data.as_slice()
636 ).unwrap();
637 let meshes = {
638 let mut v = VecMap::new();
639 for (mesh_key, line_indices_range) in line_indices_ranges.into_iter() {
640 let instanced_mesh = InstancedMesh {
641 line_indices_range,
642 instances_range: 0..0, shader_program_id: shader_program_ids[mesh_key],
644 draw_pass: draw_passes[mesh_key]
645 };
646 assert!(v.insert (mesh_key, instanced_mesh).is_none());
647 }
648 v
649 };
650 InstancedMeshes {
651 vertices, line_indices, meshes, capsule_vertex_id_offset,
652 hemisphere_vertex_count
653 }
654 }
655}
656
657impl InstancedMeshInit {
658 fn new (user_meshes : Vec <(MeshKey, Mesh, DrawPass)>) -> Self {
659 const GRID_DIMS : u16 = MESH_GRID_DIMS;
660 const HEMISPHERE_LATITUDE_DIVS : u16 = 6;
661 const SPHERE_LATITUDE_DIVS : u16 = 2 * HEMISPHERE_LATITUDE_DIVS;
662 const LONGITUDE_DIVS : u16 = 24;
663 const CYLINDER_DIVS : u16 = LONGITUDE_DIVS;
664 let mut instanced_vertex_data = Vec::new();
665 let mut instanced_line_index_data = Vec::new();
666 let mut index_offset = 0;
668 let mut index_range_start = 0;
670
671 let mut line_indices_ranges = VecMap::with_capacity (MeshId::COUNT);
672 let mut shader_program_ids = VecMap::with_capacity (MeshId::COUNT);
673 let mut draw_passes = VecMap::with_capacity (MeshId::COUNT);
674
675 let mesh::Lines3d {
677 vertices: mut grid_vertex_data, indices: mut grid_index_data
678 } = mesh::Lines3d::grid (index_offset, GRID_DIMS);
679 assert!(line_indices_ranges.insert (
680 MeshId::Grid as usize,
681 index_range_start..index_range_start + grid_index_data.len() as u32
682 ).is_none());
683 assert!(shader_program_ids.insert (
684 MeshId::Grid as usize,
685 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
686 ).is_none());
687 assert!(draw_passes.insert (MeshId::Grid as usize, DrawPass::Depth).is_none());
688 instanced_vertex_data.append (&mut grid_vertex_data);
689 instanced_line_index_data.append (&mut grid_index_data);
690 index_offset = instanced_vertex_data.len() as u32;
691 index_range_start = instanced_line_index_data.len() as u32;
692
693 let capsule_vertex_id_offset = index_offset; let mesh::Lines3d {
697 vertices: mut capsule_vertex_data,
698 indices: mut capsule_index_data
699 } = mesh::Lines3d::capsule (index_offset, HEMISPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
700 let capsule_line_indices_range =
701 index_range_start..index_range_start + capsule_index_data.len() as u32;
702 assert!(line_indices_ranges.insert (
703 MeshId::Capsule as usize, capsule_line_indices_range.clone()
704 ).is_none());
705 assert!(shader_program_ids.insert (
706 MeshId::Capsule as usize,
707 shader::ProgramId::ModelSpace3dInstancedCapsule
708 ).is_none());
709 assert!(draw_passes.insert (MeshId::Capsule as usize, DrawPass::Depth).is_none());
710 instanced_vertex_data.append (&mut capsule_vertex_data);
711 instanced_line_index_data.append (&mut capsule_index_data);
712
713 index_offset = instanced_vertex_data.len() as u32;
714 index_range_start = instanced_line_index_data.len() as u32;
715
716 let (hemisphere_vertex_count, hemisphere_index_count) =
719 mesh::hemisphere::lines3d_vertex_index_counts (
720 HEMISPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
721 assert!(line_indices_ranges.insert (
722 MeshId::Hemisphere as usize,
723 capsule_line_indices_range.start..
724 capsule_line_indices_range.start + hemisphere_index_count
725 ).is_none());
726 assert!(shader_program_ids.insert (
727 MeshId::Hemisphere as usize,
728 shader::ProgramId::ModelSpace3dInstancedScaleColor
729 ).is_none());
730 assert!(draw_passes.insert (MeshId::Hemisphere as usize, DrawPass::Depth)
731 .is_none());
732
733 let (_, sphere_index_count) = mesh::sphere::lines3d_vertex_index_counts (
736 SPHERE_LATITUDE_DIVS, LONGITUDE_DIVS);
737 assert!(line_indices_ranges.insert (
738 MeshId::Sphere as usize,
739 capsule_line_indices_range.start..
740 capsule_line_indices_range.start + sphere_index_count
741 ).is_none());
742 assert!(shader_program_ids.insert (
743 MeshId::Sphere as usize,
744 shader::ProgramId::ModelSpace3dInstancedScaleColor
745 ).is_none());
746 assert!(draw_passes.insert (MeshId::Sphere as usize, DrawPass::Depth)
747 .is_none());
748
749 let mesh::Lines3d {
751 vertices: mut cylinder_vertex_data, indices: mut cylinder_index_data
752 } = mesh::Lines3d::cylinder (index_offset, CYLINDER_DIVS);
753 assert!(line_indices_ranges.insert (
754 MeshId::Cylinder as usize,
755 index_range_start..index_range_start + cylinder_index_data.len() as u32
756 ).is_none());
757 assert!(shader_program_ids.insert (
758 MeshId::Cylinder as usize,
759 shader::ProgramId::ModelSpace3dInstancedScaleColor
760 ).is_none());
761 assert!(draw_passes.insert (MeshId::Cylinder as usize, DrawPass::Depth)
762 .is_none());
763 instanced_vertex_data.append (&mut cylinder_vertex_data);
764 instanced_line_index_data.append (&mut cylinder_index_data);
765
766 index_offset = instanced_vertex_data.len() as u32;
767 index_range_start = instanced_line_index_data.len() as u32;
768
769 let mesh::Lines3d {
771 vertices: mut cube_vertex_data, indices: mut cube_index_data
772 } = mesh::Lines3d::cube (index_offset);
773 assert!(line_indices_ranges.insert (
774 MeshId::Cube as usize,
775 index_range_start..index_range_start + cube_index_data.len() as u32
776 ).is_none());
777 assert!(shader_program_ids.insert (
778 MeshId::Cube as usize,
779 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
780 ).is_none());
781 assert!(draw_passes.insert (MeshId::Cube as usize, DrawPass::Depth).is_none());
782 instanced_vertex_data.append (&mut cube_vertex_data);
783 instanced_line_index_data.append (&mut cube_index_data);
784
785 let num_user_meshes = user_meshes.len();
792 for (mesh_key, mut mesh, draw_pass) in user_meshes {
793 debug_assert!(mesh_key.index() >= MeshId::COUNT);
794 index_offset = instanced_vertex_data.len() as u32;
795 index_range_start = instanced_line_index_data.len() as u32;
796 let mut insert_mesh = |vertices : &mut Vec <_>, indices : &mut Vec <u32>| {
797 indices.iter_mut().for_each (|ix| *ix += index_offset);
798 assert!(line_indices_ranges.insert (
799 mesh_key.index(),
800 index_range_start..index_range_start + indices.len() as u32
801 ).is_none());
802 assert!(shader_program_ids.insert (
803 mesh_key.index(),
804 shader::ProgramId::ModelSpace3dInstancedOrientationScaleColor
805 ).is_none());
806 assert!(draw_passes.insert (mesh_key.index(), draw_pass).is_none());
807 instanced_vertex_data.append (vertices);
808 instanced_line_index_data.append (indices);
809 };
810 match mesh {
811 Mesh::Points3d (mesh::Points3d { ref mut vertices, ref mut indices }) |
812 Mesh::Lines3d (mesh::Lines3d { ref mut vertices, ref mut indices }) |
813 Mesh::Triangles3d (mesh::Triangles3d { ref mut vertices, ref mut indices }) =>
814 insert_mesh (vertices, indices)
815 }
816 }
817
818 debug_assert_eq!(line_indices_ranges.len(), MeshId::COUNT + num_user_meshes);
819 debug_assert_eq!(shader_program_ids.len(), MeshId::COUNT + num_user_meshes);
820
821 InstancedMeshInit {
822 instanced_vertex_data,
823 instanced_line_index_data,
824 line_indices_ranges,
825 shader_program_ids,
826 draw_passes,
827 capsule_vertex_id_offset,
828 hemisphere_vertex_count
829 }
830 }
831}
832
833impl MeshKey {
834 pub const fn index (self) -> usize {
835 self.0 as usize
836 }
837}
838
839impl UserBufferKey {
840 pub const fn index (self) -> usize {
841 self.0 as usize
842 }
843}