1use std::{
4 collections::HashMap,
5 f32::consts::TAU,
6 fs::File,
7 io::{BufReader, Read},
8};
9
10use lin_alg::f32::Vec3;
11
12use crate::{
13 graphics::UP_VEC,
14 types::{Mesh, Vertex},
15};
16
17fn rotate_vec_2d(vec: [f32; 2], θ: f32) -> [f32; 2] {
19 let (sin_θ, cos_θ) = θ.sin_cos();
21 let mat = [cos_θ, sin_θ, -sin_θ, cos_θ];
22
23 [
24 vec[0] * mat[0] + vec[1] * mat[2],
25 vec[0] * mat[1] + vec[1] * mat[3],
26 ]
27}
28
29impl Mesh {
30 pub fn new_surface(points: &Vec<Vec<Vec3>>, two_sided: bool) -> Self {
64 let mut vertices = Vec::new();
65 let mut indices = Vec::new();
66
67 let mut this_vert_i = 0;
69
70 for (i, rows) in points.into_iter().enumerate() {
72 for (j, point) in rows.into_iter().enumerate() {
73 let x = point.x;
74 let y = point.z; let z = point.y;
76
77 vertices.push(Vertex::new([x, y, z], Vec3::new_zero()));
81
82 if i != points.len() - 1 && j != rows.len() - 1 {
89 indices.append(&mut vec![
90 this_vert_i,
91 this_vert_i + points.len(),
92 this_vert_i + 1,
93 ]);
94 }
95
96 if i != 0 && j != 0 {
99 indices.append(&mut vec![
100 this_vert_i,
101 this_vert_i - points.len(),
102 this_vert_i - 1,
103 ]);
104 }
105
106 this_vert_i += 1;
108 }
110 }
112
113 for i in 0..indices.len() / 3 {
115 let tri_start_i = i * 3;
116 let vert0 = vertices[indices[tri_start_i]];
118 let vert1 = vertices[indices[tri_start_i + 1]];
119 let vert2 = vertices[indices[tri_start_i + 2]];
120
121 let v0 = Vec3::new(vert0.position[0], vert0.position[1], vert0.position[2]);
123 let v1 = Vec3::new(vert1.position[0], vert1.position[1], vert1.position[2]);
124 let v2 = Vec3::new(vert2.position[0], vert2.position[1], vert2.position[2]);
125
126 let norm = (v2 - v0).to_normalized().cross((v1 - v0).to_normalized());
127
128 vertices[indices[tri_start_i]].normal = norm;
130 vertices[indices[tri_start_i + 1]].normal = norm;
131 vertices[indices[tri_start_i + 1]].normal = norm;
132 }
133
134 if two_sided {
137 let orig_vert_len = vertices.len();
138 let mut vertices_other_side = Vec::new();
139 for vertex in &vertices {
140 let mut new_vertex = vertex.clone();
141 new_vertex.normal *= -1.;
142 vertices_other_side.push(new_vertex);
143 }
144 vertices.append(&mut vertices_other_side);
145
146 let mut new_indices = Vec::new();
147 for i in 0..indices.len() / 3 {
148 let tri_start_i = i * 3;
149 new_indices.push(indices[tri_start_i] + orig_vert_len);
151 new_indices.push(indices[tri_start_i + 2] + orig_vert_len);
152 new_indices.push(indices[tri_start_i + 1] + orig_vert_len);
153 }
154 indices.append(&mut new_indices);
155 }
156
157 Self {
158 vertices,
159 indices,
160 material: 0,
161 }
162 }
163
164 pub fn new_sphere(radius: f32, mut subdivisions: u32) -> Self {
166 if subdivisions > 4 {
167 println!(
168 "Warning: Sphere subdivisions > 4 is not allowed due to extreme performance cost. Setting to 4."
169 );
170 subdivisions = 4;
171 }
172 let mut vertices = Vec::new();
173 let mut indices = Vec::new();
174
175 let t = (1.0 + 5.0_f32.sqrt()) / 2.0;
178
179 let mut initial_points = vec![
180 Vec3::new(-1.0, t, 0.0),
181 Vec3::new(1.0, t, 0.0),
182 Vec3::new(-1.0, -t, 0.0),
183 Vec3::new(1.0, -t, 0.0),
184 Vec3::new(0.0, -1.0, t),
185 Vec3::new(0.0, 1.0, t),
186 Vec3::new(0.0, -1.0, -t),
187 Vec3::new(0.0, 1.0, -t),
188 Vec3::new(t, 0.0, -1.0),
189 Vec3::new(t, 0.0, 1.0),
190 Vec3::new(-t, 0.0, -1.0),
191 Vec3::new(-t, 0.0, 1.0),
192 ];
193
194 for point in &mut initial_points {
196 *point = point.to_normalized() * radius;
197 vertices.push(Vertex::new(point.to_arr(), point.to_normalized()));
198 }
199
200 let mut faces = vec![
202 [0, 11, 5],
203 [0, 5, 1],
204 [0, 1, 7],
205 [0, 7, 10],
206 [0, 10, 11],
207 [1, 5, 9],
208 [5, 11, 4],
209 [11, 10, 2],
210 [10, 7, 6],
211 [7, 1, 8],
212 [3, 9, 4],
213 [3, 4, 2],
214 [3, 2, 6],
215 [3, 6, 8],
216 [3, 8, 9],
217 [4, 9, 5],
218 [2, 4, 11],
219 [6, 2, 10],
220 [8, 6, 7],
221 [9, 8, 1],
222 ];
223
224 let mut middle_point_cache = HashMap::<(usize, usize), usize>::new();
226
227 let mut get_middle_point = |a: usize, b: usize| -> usize {
230 let key = if a < b { (a, b) } else { (b, a) };
231 if let Some(&index) = middle_point_cache.get(&key) {
232 return index;
233 }
234 let point_a = Vec3::from_slice(&vertices[a].position).unwrap();
235 let point_b = Vec3::from_slice(&vertices[b].position).unwrap();
236 let middle = (point_a + point_b) * 0.5;
237 let normalized = middle.to_normalized() * radius;
238 let index = vertices.len();
239 vertices.push(Vertex::new(normalized.to_arr(), normalized.to_normalized()));
240 middle_point_cache.insert(key, index);
241 index
242 };
243
244 for _ in 0..subdivisions {
247 let mut new_faces = Vec::new();
248 for tri in &faces {
249 let a = tri[0];
250 let b = tri[1];
251 let c = tri[2];
252
253 let ab = get_middle_point(a, b);
254 let bc = get_middle_point(b, c);
255 let ca = get_middle_point(c, a);
256
257 new_faces.push([a, ca, ab]);
258 new_faces.push([b, ab, bc]);
259 new_faces.push([c, bc, ca]);
260 new_faces.push([ab, ca, bc]);
261 }
262 faces = new_faces;
263 }
264
265 for face in &mut faces {
267 if subdivisions % 2 == 0 {
268 let first = face[0];
269 face[0] = face[1];
270 face[1] = first;
271 }
272 indices.extend_from_slice(face);
273 }
274
275 Self {
276 vertices,
277 indices,
278 material: 0,
279 }
280 }
281
282 pub fn new_sphere_uv(radius: f32, num_lats: usize, num_lons: usize) -> Self {
285 let mut vertices = Vec::new();
286 let mut faces = Vec::new();
288 let mut indices = Vec::new();
289
290 let lat_size = TAU / (2. * num_lats as f32);
292 let lon_size = TAU / num_lons as f32;
293
294 let mut current_i = 0;
295
296 vertices.push(Vertex::new([0., -radius, 0.], Vec3::new(0., -1., 0.)));
298 current_i += 1;
299
300 for k in 0..num_lons {
302 if k == num_lons - 1 {
303 indices.append(&mut vec![0, k + 2 - num_lons, k + 1]);
304 } else {
305 indices.append(&mut vec![0, k + 2, k + 1]);
306 }
307 }
308
309 for i in 1..num_lats {
311 let θ = i as f32 * lat_size;
312
313 for j in 0..num_lons {
314 let φ = j as f32 * lon_size;
315
316 let x = radius * φ.cos() * θ.sin();
318 let y = radius * φ.sin() * θ.sin();
319 let z = radius * θ.cos();
320
321 vertices.push(Vertex::new([x, y, z], Vec3::new(x, y, z).to_normalized()));
322
323 if i < num_lats - 1 {
324 if j == num_lons - 1 {
326 faces.push([
327 current_i,
328 current_i + 1 - num_lons,
329 current_i + 1,
330 current_i + num_lons,
331 ]);
332 } else {
333 faces.push([
334 current_i,
335 current_i + 1,
336 current_i + num_lons + 1,
337 current_i + num_lons,
338 ]);
339 }
340 }
341 current_i += 1;
342 }
343 }
344
345 vertices.push(Vertex::new([0., radius, 0.], Vec3::new(0., 1., 0.)));
347
348 let top_ring_start_i = current_i - num_lons;
350
351 for k in 0..num_lons {
355 if k == num_lons - 1 {
356 indices.append(&mut vec![current_i, top_ring_start_i + k, top_ring_start_i]);
357 } else {
358 indices.append(&mut vec![
359 current_i,
360 top_ring_start_i + k,
361 top_ring_start_i + k + 1,
362 ]);
363 }
364 }
365
366 for f in faces {
367 indices.append(&mut vec![f[0], f[1], f[2], f[0], f[2], f[3]]);
368 }
369
370 Self {
371 vertices,
372 indices,
373 material: 0,
374 }
375 }
376
377 pub fn new_ring(len: f32, radius_inner: f32, radius_outer: f32, num_sides: usize) -> Self {
380 let angle_between_vertices = TAU / num_sides as f32;
381
382 let mut circle_vertices_inner = Vec::new();
383 for i in 0..num_sides {
384 circle_vertices_inner.push(rotate_vec_2d(
385 [radius_inner, 0.],
386 i as f32 * angle_between_vertices,
387 ));
388 }
389
390 let mut circle_vertices_outer = Vec::new();
392 for i in 0..num_sides {
393 circle_vertices_outer.push(rotate_vec_2d(
394 [radius_outer, 0.],
395 i as f32 * angle_between_vertices,
396 ));
397 }
398
399 let half_len = len * 0.5;
400 let mod_ = 2 * num_sides;
401
402 let mut vertices = Vec::new();
403 let mut indices = Vec::new();
404
405 let mut i_vertex = 0;
406
407 for vert in &circle_vertices_inner {
409 indices.append(&mut vec![i_vertex, i_vertex + 1, (i_vertex + 2) % mod_]);
412 indices.append(&mut vec![
414 i_vertex + 1,
416 (i_vertex + 2) % mod_,
417 (i_vertex + 3) % mod_,
418 ]);
419
420 vertices.push(Vertex::new(
422 [vert[0], half_len, vert[1]],
423 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
424 ));
425 i_vertex += 1;
426
427 vertices.push(Vertex::new(
429 [vert[0], -half_len, vert[1]],
430 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
431 ));
432 i_vertex += 1;
433 }
434
435 for vert in &circle_vertices_outer {
437 indices.append(&mut vec![i_vertex, i_vertex + 1, (i_vertex + 2) % mod_]);
440 indices.append(&mut vec![
442 i_vertex + 1,
443 (i_vertex + 3) % mod_,
444 (i_vertex + 2) % mod_,
445 ]);
446
447 vertices.push(Vertex::new(
449 [vert[0], half_len, vert[1]],
450 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
451 ));
452 i_vertex += 1;
453
454 vertices.push(Vertex::new(
456 [vert[0], -half_len, vert[1]],
457 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
458 ));
459 i_vertex += 1;
460 }
461
462 let top_anchor = i_vertex;
463 let bottom_anchor = i_vertex + 1;
464
465 Self {
483 vertices,
484 indices,
485 material: 0,
486 }
487 }
488
489 pub fn new_box(len_x: f32, len_y: f32, len_z: f32) -> Self {
491 let x = len_x / 2.;
492 let y = len_y / 2.;
493 let z = len_z / 2.;
494
495 let abl = [-x, -y, -z];
497 let abr = [x, -y, -z];
498 let atr = [x, y, -z];
499 let atl = [-x, y, -z];
500
501 let fbl = [-x, -y, z];
503 let fbr = [x, -y, z];
504 let ftr = [x, y, z];
505 let ftl = [-x, y, z];
506
507 let aft = Vec3::new(0., 0., -1.);
509 let fwd = Vec3::new(0., 0., 1.);
510 let l = Vec3::new(-1., 0., 0.);
511 let r = Vec3::new(1., 0., 0.);
512 let t = Vec3::new(0., 1., 0.);
513 let b = Vec3::new(0., -1., 0.);
514
515 let vertices = vec![
516 Vertex::new(abl, aft),
518 Vertex::new(abr, aft),
519 Vertex::new(atr, aft),
520 Vertex::new(atl, aft),
521 Vertex::new(fbl, fwd),
523 Vertex::new(ftl, fwd),
524 Vertex::new(ftr, fwd),
525 Vertex::new(fbr, fwd),
526 Vertex::new(fbl, l),
528 Vertex::new(abl, l),
529 Vertex::new(atl, l),
530 Vertex::new(ftl, l),
531 Vertex::new(abr, r),
533 Vertex::new(fbr, r),
534 Vertex::new(ftr, r),
535 Vertex::new(atr, r),
536 Vertex::new(atl, t),
538 Vertex::new(atr, t),
539 Vertex::new(ftr, t),
540 Vertex::new(ftl, t),
541 Vertex::new(abl, b),
543 Vertex::new(fbl, b),
544 Vertex::new(fbr, b),
545 Vertex::new(abr, b),
546 ];
547
548 let faces = [
549 [0, 1, 2, 3],
550 [4, 5, 6, 7],
551 [8, 9, 10, 11],
552 [12, 13, 14, 15],
553 [16, 17, 18, 19],
554 [20, 21, 22, 23],
555 ];
556
557 let mut indices = Vec::new();
558 for face in &faces {
559 indices.append(&mut vec![
560 face[0], face[1], face[2], face[0], face[2], face[3],
561 ]);
562 }
563
564 Self {
565 vertices,
566 indices,
567 material: 0,
568 }
569 }
570
571 pub fn new_tetrahedron(side_len: f32) -> Self {
573 let c = side_len / 2.;
574
575 let v_0 = [c, c, c];
576 let v_1 = [c, -c, -c];
577 let v_2 = [-c, c, -c];
578 let v_3 = [-c, -c, c];
579
580 let n_0 = Vec3::new(1., 1., -1.).to_normalized();
583 let n_1 = Vec3::new(1., -1., 1.).to_normalized();
584 let n_2 = Vec3::new(-1., 1., 1.).to_normalized();
585 let n_3 = Vec3::new(-1., -1., -1.).to_normalized();
586
587 let vertices = vec![
588 Vertex::new(v_0, n_0),
590 Vertex::new(v_2, n_0),
591 Vertex::new(v_1, n_0),
592 Vertex::new(v_0, n_1),
594 Vertex::new(v_1, n_1),
595 Vertex::new(v_3, n_1),
596 Vertex::new(v_0, n_2),
598 Vertex::new(v_3, n_2),
599 Vertex::new(v_2, n_2),
600 Vertex::new(v_1, n_3),
602 Vertex::new(v_2, n_3),
603 Vertex::new(v_3, n_3),
604 ];
605
606 #[rustfmt::skip]
611 let indices = vec![
613 0, 1, 2,
614 3, 4, 5,
615 6, 7, 8,
616 9, 10, 11,
617 ];
618
619 Self {
620 vertices,
621 indices,
622 material: 0,
626 }
627 }
628
629 pub fn new_cylinder(len: f32, radius: f32, num_sides: usize) -> Self {
631 let angle_between_vertices = TAU / num_sides as f32;
632
633 let mut circle_vertices = Vec::new();
634 for i in 0..num_sides {
635 circle_vertices.push(rotate_vec_2d(
636 [radius, 0.],
637 i as f32 * angle_between_vertices,
638 ));
639 }
640
641 let half_len = len * 0.5;
642 let mod_ = 2 * num_sides;
643
644 let mut vertices = Vec::new();
645 let mut indices = Vec::new();
646
647 let mut i_vertex = 0;
648
649 for vert in &circle_vertices {
651 indices.append(&mut vec![i_vertex, i_vertex + 1, (i_vertex + 2) % mod_]);
654 indices.append(&mut vec![
656 i_vertex + 1,
657 (i_vertex + 3) % mod_,
658 (i_vertex + 2) % mod_,
659 ]);
660
661 vertices.push(Vertex::new(
663 [vert[0], half_len, vert[1]],
664 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
665 ));
666 i_vertex += 1;
667
668 vertices.push(Vertex::new(
670 [vert[0], -half_len, vert[1]],
671 Vec3::new(vert[0], 0., vert[1]).to_normalized(),
672 ));
673 i_vertex += 1;
674 }
675
676 let top_anchor = i_vertex;
677 let bottom_anchor = i_vertex + 1;
678
679 for (j, vert) in circle_vertices.iter().enumerate() {
680 if j != 0 && j != num_sides - 1 {
682 indices.append(&mut vec![top_anchor, i_vertex, i_vertex + 2]);
683 indices.append(&mut vec![bottom_anchor, i_vertex + 3, i_vertex + 1]);
685 }
686
687 vertices.push(Vertex::new([vert[0], half_len, vert[1]], UP_VEC));
689 i_vertex += 1;
690
691 vertices.push(Vertex::new([vert[0], -half_len, vert[1]], -UP_VEC));
693 i_vertex += 1;
694 }
695
696 Self {
697 vertices,
698 indices,
699 material: 0,
700 }
701 }
702
703 pub fn new_pyramid(len: f32, radius: f32, num_sides: usize) -> Self {
704 let angle_between_vertices = TAU / num_sides as f32;
706
707 let mut circle_vertices = Vec::new();
708 for i in 0..num_sides {
709 circle_vertices.push(rotate_vec_2d(
710 [radius, 0.],
711 i as f32 * angle_between_vertices,
712 ));
713 }
714
715 let half_len = len * 0.5;
716
717 let mut vertices = Vec::new();
718 let mut indices = Vec::new();
719
720 let tip = 0;
721
722 let mut i_vertex = 0;
723
724 vertices.push(Vertex::new([0., half_len, 0.], UP_VEC));
726 i_vertex += 1;
727
728 indices.push(tip);
729
730 for (j, vert) in circle_vertices.iter().enumerate() {
732 let next = if j == num_sides - 1 {
735 i_vertex + 1 - num_sides } else {
737 i_vertex + 1
738 };
739 indices.append(&mut vec![i_vertex, next, tip]);
741
742 vertices.push(Vertex::new(
743 [vert[0], -half_len, vert[1]],
744 Vec3::new(vert[0], len, vert[1]).to_normalized(),
745 ));
746 i_vertex += 1;
747 }
748
749 let bottom_anchor = i_vertex; for (j, vert) in circle_vertices.iter().enumerate() {
753 if j != 0 && j != num_sides - 1 {
755 indices.append(&mut vec![bottom_anchor, i_vertex + 1, i_vertex]);
756 }
757
758 vertices.push(Vertex::new([vert[0], -half_len, vert[1]], -UP_VEC));
759 i_vertex += 1;
760 }
761
762 Self {
763 vertices,
764 indices,
765 material: 0,
766 }
767 }
768
769 pub fn new_arrow(len: f32, radius: f32, num_sides: usize) -> Self {
771 let tip_offset = len / 2.;
772 let cylinder = Self::new_cylinder(len, radius, num_sides);
773
774 let tip = Self::new_pyramid(len * 0.5, radius * 3., num_sides);
775
776 let mut vertices = cylinder.vertices.clone();
777 let mut indices = cylinder.indices.clone();
778
779 for vertex in tip.vertices {
780 vertices.push(Vertex {
781 position: [
782 vertex.position[0],
783 vertex.position[1] + tip_offset,
784 vertex.position[2],
785 ],
786 ..vertex
787 });
788 }
789
790 let ci2 = cylinder.indices.clone();
791 let tip_start_index = ci2.iter().max().unwrap() + 1;
792
793 for index in tip.indices {
794 indices.push(index + tip_start_index);
795 }
796
797 Self {
798 vertices,
799 indices,
800 material: 0,
801 }
802 }
803
804 pub fn from_obj(obj_data: &[u8]) -> Self {
808 let data = obj::ObjData::load_buf(&obj_data[..]).unwrap();
809 let mut vertices = Vec::new();
810
811 for object in data.objects {
812 for group in object.groups {
813 vertices.clear();
814
815 for poly in group.polys {
816 for end_index in 2..poly.0.len() {
817 for &index in &[0, end_index - 1, end_index] {
818 let obj::IndexTuple(position_id, _texture_id, normal_id) =
819 poly.0[index];
820
821 let n = data.normal[normal_id.unwrap()];
822
823 vertices.push(Vertex::new(
824 data.position[position_id],
825 Vec3::new(n[0], n[1], n[2]),
826 ));
827 }
828 }
829 }
830 }
831 }
832
833 let indices = (0..vertices.len()).collect();
835
836 Self {
837 vertices,
838 indices,
839 material: 0,
840 }
841 }
842
843 pub fn from_obj_file(filename: &str) -> Self {
847 let f = File::open(filename).unwrap();
849 let mut reader = BufReader::new(f);
850 let mut file_buf = Vec::new();
851
852 reader.read_to_end(&mut file_buf).unwrap();
853
854 Self::from_obj(&file_buf)
855 }
856}