1use crate::components::Mesh;
2use crate::renderer::Vertex;
3use gizmo_math::Vec3;
4use std::sync::Arc;
5use wgpu::util::DeviceExt;
6
7impl super::AssetManager {
8 pub fn create_inverted_cube(device: &wgpu::Device) -> Mesh {
11 let positions: [[f32; 3]; 8] = [
14 [-1.0, -1.0, -1.0], [1.0, -1.0, -1.0], [1.0, 1.0, -1.0], [-1.0, 1.0, -1.0], [-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], ];
23
24 struct FaceDef {
25 indices: [usize; 6],
26 normal: [f32; 3],
27 uvs: [[f32; 2]; 6],
28 }
29
30 let faces: [FaceDef; 6] = [
31 FaceDef {
33 indices: [0, 1, 2, 0, 2, 3],
34 normal: [0.0, 0.0, 1.0],
35 uvs: [
36 [1.0, 1.0],
37 [0.0, 1.0],
38 [0.0, 0.0],
39 [1.0, 1.0],
40 [0.0, 0.0],
41 [1.0, 0.0],
42 ],
43 },
44 FaceDef {
46 indices: [4, 6, 5, 4, 7, 6],
47 normal: [0.0, 0.0, -1.0],
48 uvs: [
49 [0.0, 1.0],
50 [1.0, 0.0],
51 [1.0, 1.0],
52 [0.0, 1.0],
53 [0.0, 0.0],
54 [1.0, 0.0],
55 ],
56 },
57 FaceDef {
59 indices: [0, 5, 1, 0, 4, 5],
60 normal: [0.0, 1.0, 0.0],
61 uvs: [
62 [0.0, 0.0],
63 [1.0, 1.0],
64 [1.0, 0.0],
65 [0.0, 0.0],
66 [0.0, 1.0],
67 [1.0, 1.0],
68 ],
69 },
70 FaceDef {
72 indices: [3, 2, 6, 3, 6, 7],
73 normal: [0.0, -1.0, 0.0],
74 uvs: [
75 [0.0, 0.0],
76 [1.0, 0.0],
77 [1.0, 1.0],
78 [0.0, 0.0],
79 [1.0, 1.0],
80 [0.0, 1.0],
81 ],
82 },
83 FaceDef {
85 indices: [0, 3, 7, 0, 7, 4],
86 normal: [1.0, 0.0, 0.0],
87 uvs: [
88 [0.0, 1.0],
89 [0.0, 0.0],
90 [1.0, 0.0],
91 [0.0, 1.0],
92 [1.0, 0.0],
93 [1.0, 1.0],
94 ],
95 },
96 FaceDef {
98 indices: [1, 6, 2, 1, 5, 6],
99 normal: [-1.0, 0.0, 0.0],
100 uvs: [
101 [1.0, 1.0],
102 [0.0, 0.0],
103 [1.0, 0.0],
104 [1.0, 1.0],
105 [0.0, 1.0],
106 [0.0, 0.0],
107 ],
108 },
109 ];
110
111 let mut vertices = Vec::with_capacity(36);
112 for face in &faces {
113 for i in 0..6 {
114 vertices.push(Vertex {
115 position: positions[face.indices[i]],
116 color: [1.0, 1.0, 1.0],
117 normal: face.normal,
118 tex_coords: face.uvs[i],
119 joint_indices: [0; 4],
120 joint_weights: [0.0; 4], ..Default::default()
121 });
122 }
123 }
124
125 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
126 label: Some("Skybox Inverted Cube VBuf"),
127 contents: bytemuck::cast_slice(&vertices),
128 usage: wgpu::BufferUsages::VERTEX,
129 });
130
131 Mesh::new(
132 device,
133 Arc::new(vbuf),
134 &vertices,
135 Vec3::ZERO,
136 "inverted_cube".to_string(),
137 )
138 }
139
140 pub fn create_cube(device: &wgpu::Device) -> Mesh {
142 let positions: [[f32; 3]; 8] = [
143 [-1.0, -1.0, -1.0], [1.0, -1.0, -1.0], [1.0, 1.0, -1.0], [-1.0, 1.0, -1.0], [-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], ];
152
153 struct FaceDef {
154 indices: [usize; 6],
155 normal: [f32; 3],
156 uvs: [[f32; 2]; 6],
157 }
158
159 let faces: [FaceDef; 6] = [
160 FaceDef {
162 indices: [1, 0, 3, 1, 3, 2],
163 normal: [0.0, 0.0, -1.0],
164 uvs: [
165 [0.0, 1.0],
166 [1.0, 1.0],
167 [1.0, 0.0],
168 [0.0, 1.0],
169 [1.0, 0.0],
170 [0.0, 0.0],
171 ],
172 },
173 FaceDef {
175 indices: [4, 5, 6, 4, 6, 7],
176 normal: [0.0, 0.0, 1.0],
177 uvs: [
178 [0.0, 1.0],
179 [1.0, 1.0],
180 [1.0, 0.0],
181 [0.0, 1.0],
182 [1.0, 0.0],
183 [0.0, 0.0],
184 ],
185 },
186 FaceDef {
188 indices: [0, 1, 5, 0, 5, 4],
189 normal: [0.0, -1.0, 0.0],
190 uvs: [
191 [0.0, 0.0],
192 [1.0, 0.0],
193 [1.0, 1.0],
194 [0.0, 0.0],
195 [1.0, 1.0],
196 [0.0, 1.0],
197 ],
198 },
199 FaceDef {
201 indices: [7, 6, 2, 7, 2, 3],
202 normal: [0.0, 1.0, 0.0],
203 uvs: [
204 [0.0, 1.0],
205 [1.0, 1.0],
206 [1.0, 0.0],
207 [0.0, 1.0],
208 [1.0, 0.0],
209 [0.0, 0.0],
210 ],
211 },
212 FaceDef {
214 indices: [0, 4, 7, 0, 7, 3],
215 normal: [-1.0, 0.0, 0.0],
216 uvs: [
217 [0.0, 1.0],
218 [1.0, 1.0],
219 [1.0, 0.0],
220 [0.0, 1.0],
221 [1.0, 0.0],
222 [0.0, 0.0],
223 ],
224 },
225 FaceDef {
227 indices: [5, 1, 2, 5, 2, 6],
228 normal: [1.0, 0.0, 0.0],
229 uvs: [
230 [0.0, 1.0],
231 [1.0, 1.0],
232 [1.0, 0.0],
233 [0.0, 1.0],
234 [1.0, 0.0],
235 [0.0, 0.0],
236 ],
237 },
238 ];
239
240 let mut vertices = Vec::with_capacity(36);
241 for face in &faces {
242 for i in 0..6 {
243 vertices.push(Vertex {
244 position: positions[face.indices[i]],
245 color: [1.0, 1.0, 1.0],
246 normal: face.normal,
247 tex_coords: face.uvs[i],
248 joint_indices: [0; 4],
249 joint_weights: [0.0; 4], ..Default::default()
250 });
251 }
252 }
253
254 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
255 label: Some("Standard Cube VBuf"),
256 contents: bytemuck::cast_slice(&vertices),
257 usage: wgpu::BufferUsages::VERTEX,
258 });
259
260 Mesh::new(
261 device,
262 Arc::new(vbuf),
263 &vertices,
264 Vec3::ZERO,
265 "standard_cube".to_string(),
266 )
267 }
268
269 pub fn create_gizmo_arrow(device: &wgpu::Device) -> Mesh {
270 let w = 0.03; let hw = 0.12; let sl = 0.8; let positions: [[f32; 3]; 13] = [
275 [-w, 0.0, -w],
277 [w, 0.0, -w],
278 [w, sl, -w],
279 [-w, sl, -w],
280 [-w, 0.0, w],
281 [w, 0.0, w],
282 [w, sl, w],
283 [-w, sl, w],
284 [-hw, sl, -hw],
286 [hw, sl, -hw],
287 [hw, sl, hw],
288 [-hw, sl, hw],
289 [0.0, 1.0, 0.0],
291 ];
292
293 let head_dy = 1.0 - sl;
294 let head_dxz = hw;
295 let head_norm_len = (head_dy * head_dy + head_dxz * head_dxz).sqrt();
296 let n_y = head_dxz / head_norm_len;
297 let n_xz = head_dy / head_norm_len;
298
299 let faces: Vec<(Vec<usize>, [f32; 3])> = vec![
301 (vec![0, 2, 1, 0, 3, 2], [0.0, 0.0, -1.0]), (vec![4, 5, 6, 4, 6, 7], [0.0, 0.0, 1.0]), (vec![0, 1, 5, 0, 5, 4], [0.0, -1.0, 0.0]), (vec![0, 4, 7, 0, 7, 3], [-1.0, 0.0, 0.0]), (vec![1, 2, 6, 1, 6, 5], [1.0, 0.0, 0.0]), (vec![8, 9, 10, 8, 10, 11], [0.0, -1.0, 0.0]),
309 (vec![11, 10, 12], [0.0, n_y, n_xz]), (vec![9, 8, 12], [0.0, n_y, -n_xz]), (vec![10, 9, 12], [n_xz, n_y, 0.0]), (vec![8, 11, 12], [-n_xz, n_y, 0.0]), ];
315
316 let mut vertices = Vec::new();
317 for (indices, normal) in faces {
318 for idx in indices {
319 vertices.push(Vertex {
320 position: positions[idx],
321 color: [1.0, 1.0, 1.0],
322 normal,
323 tex_coords: [0.0, 0.0],
324 joint_indices: [0; 4],
325 joint_weights: [0.0; 4], ..Default::default()
326 });
327 }
328 }
329
330 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
331 label: Some("Gizmo Arrow VBuf"),
332 contents: bytemuck::cast_slice(&vertices),
333 usage: wgpu::BufferUsages::VERTEX,
334 });
335
336 Mesh::new(
337 device,
338 Arc::new(vbuf),
339 &vertices,
340 Vec3::ZERO,
341 "gizmo_arrow".to_string(),
342 )
343 }
344
345 pub fn create_plane(device: &wgpu::Device, size: f32) -> Mesh {
347 let half = size / 2.0;
348 let y = 0.0;
349
350 let def_j = [0; 4];
352 let def_w = [0.0; 4];
353 let vertices = [
354 Vertex {
356 position: [-half, y, -half],
357 color: [1.0, 1.0, 1.0],
358 normal: [0.0, 1.0, 0.0],
359 tex_coords: [0.0, 0.0],
360 joint_indices: def_j,
361 joint_weights: def_w, ..Default::default()
362 },
363 Vertex {
364 position: [half, y, -half],
365 color: [1.0, 1.0, 1.0],
366 normal: [0.0, 1.0, 0.0],
367 tex_coords: [size, 0.0],
368 joint_indices: def_j,
369 joint_weights: def_w, ..Default::default()
370 },
371 Vertex {
372 position: [half, y, half],
373 color: [1.0, 1.0, 1.0],
374 normal: [0.0, 1.0, 0.0],
375 tex_coords: [size, size],
376 joint_indices: def_j,
377 joint_weights: def_w, ..Default::default()
378 },
379 Vertex {
381 position: [-half, y, -half],
382 color: [1.0, 1.0, 1.0],
383 normal: [0.0, 1.0, 0.0],
384 tex_coords: [0.0, 0.0],
385 joint_indices: def_j,
386 joint_weights: def_w, ..Default::default()
387 },
388 Vertex {
389 position: [half, y, half],
390 color: [1.0, 1.0, 1.0],
391 normal: [0.0, 1.0, 0.0],
392 tex_coords: [size, size],
393 joint_indices: def_j,
394 joint_weights: def_w, ..Default::default()
395 },
396 Vertex {
397 position: [-half, y, half],
398 color: [1.0, 1.0, 1.0],
399 normal: [0.0, 1.0, 0.0],
400 tex_coords: [0.0, size],
401 joint_indices: def_j,
402 joint_weights: def_w, ..Default::default()
403 },
404 ];
405
406 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
407 label: Some("Plane VBuf"),
408 contents: bytemuck::cast_slice(&vertices),
409 usage: wgpu::BufferUsages::VERTEX,
410 });
411
412 Mesh::new(
413 device,
414 Arc::new(vbuf),
415 &vertices,
416 Vec3::ZERO,
417 format!("plane_{}", size),
418 )
419 }
420
421 pub fn create_circle(device: &wgpu::Device, radius: f32, segments: u32) -> Mesh {
423 let segments = segments.max(3);
424 let mut vertices = Vec::with_capacity((segments * 3) as usize);
425
426 let center = [0.0, 0.0, 0.0];
427 let normal = [0.0, 1.0, 0.0];
428 let def_j = [0; 4];
429 let def_w = [0.0; 4];
430
431 for i in 0..segments {
432 let angle1 = (i as f32 / segments as f32) * std::f32::consts::PI * 2.0;
433 let angle2 = ((i + 1) as f32 / segments as f32) * std::f32::consts::PI * 2.0;
434
435 let p1 = [radius * angle1.cos(), 0.0, radius * angle1.sin()];
436 let p2 = [radius * angle2.cos(), 0.0, radius * angle2.sin()];
437
438 let uv_center = [0.5, 0.5];
439 let uv1 = [0.5 + 0.5 * angle1.cos(), 0.5 + 0.5 * angle1.sin()];
440 let uv2 = [0.5 + 0.5 * angle2.cos(), 0.5 + 0.5 * angle2.sin()];
441
442 vertices.push(Vertex {
444 position: center,
445 color: [1.0, 1.0, 1.0],
446 normal,
447 tex_coords: uv_center,
448 joint_indices: def_j,
449 joint_weights: def_w, ..Default::default()
450 });
451 vertices.push(Vertex {
452 position: p1,
453 color: [1.0, 1.0, 1.0],
454 normal,
455 tex_coords: uv1,
456 joint_indices: def_j,
457 joint_weights: def_w, ..Default::default()
458 });
459 vertices.push(Vertex {
460 position: p2,
461 color: [1.0, 1.0, 1.0],
462 normal,
463 tex_coords: uv2,
464 joint_indices: def_j,
465 joint_weights: def_w, ..Default::default()
466 });
467 }
468
469 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
470 label: Some("Circle VBuf"),
471 contents: bytemuck::cast_slice(&vertices),
472 usage: wgpu::BufferUsages::VERTEX,
473 });
474
475 Mesh::new(
476 device,
477 Arc::new(vbuf),
478 &vertices,
479 Vec3::ZERO,
480 format!("circle_{}_{}", radius, segments),
481 )
482 }
483
484 pub fn create_editor_grid_mesh(device: &wgpu::Device, extents: f32) -> Mesh {
486 let mut vertices = Vec::new();
487 let scale = extents;
489 let v = [
490 [-scale, 0.0, -scale],
491 [scale, 0.0, -scale],
492 [scale, 0.0, scale],
493 [-scale, 0.0, scale],
494 ];
495
496 let indices = [0, 2, 1, 0, 3, 2];
497 for i in indices {
498 vertices.push(Vertex {
499 position: v[i],
500 color: [1.0, 1.0, 1.0],
501 normal: [0.0, 1.0, 0.0],
502 tex_coords: [0.0, 0.0],
503 joint_indices: [0; 4],
504 joint_weights: [0.0; 4], ..Default::default()
505 });
506 }
507
508 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
509 label: Some("Editor Infinite Grid VBuf"),
510 contents: bytemuck::cast_slice(&vertices),
511 usage: wgpu::BufferUsages::VERTEX,
512 });
513
514 Mesh::new(
515 device,
516 Arc::new(vbuf),
517 &vertices,
518 Vec3::ZERO,
519 "editor_grid".to_string(),
520 )
521 }
522
523 pub fn create_sprite_quad(device: &wgpu::Device, width: f32, height: f32) -> Mesh {
526 let hw = width / 2.0;
527 let hh = height / 2.0;
528 let def_j = [0; 4];
529 let def_w = [0.0; 4];
530
531 let vertices = [
533 Vertex {
534 position: [-hw, -hh, 0.0],
535 color: [1.0, 1.0, 1.0],
536 normal: [0.0, 0.0, 1.0],
537 tex_coords: [0.0, 1.0],
538 joint_indices: def_j,
539 joint_weights: def_w, ..Default::default()
540 },
541 Vertex {
542 position: [hw, -hh, 0.0],
543 color: [1.0, 1.0, 1.0],
544 normal: [0.0, 0.0, 1.0],
545 tex_coords: [1.0, 1.0],
546 joint_indices: def_j,
547 joint_weights: def_w, ..Default::default()
548 },
549 Vertex {
550 position: [hw, hh, 0.0],
551 color: [1.0, 1.0, 1.0],
552 normal: [0.0, 0.0, 1.0],
553 tex_coords: [1.0, 0.0],
554 joint_indices: def_j,
555 joint_weights: def_w, ..Default::default()
556 },
557 Vertex {
558 position: [hw, hh, 0.0],
559 color: [1.0, 1.0, 1.0],
560 normal: [0.0, 0.0, 1.0],
561 tex_coords: [1.0, 0.0],
562 joint_indices: def_j,
563 joint_weights: def_w, ..Default::default()
564 },
565 Vertex {
566 position: [-hw, hh, 0.0],
567 color: [1.0, 1.0, 1.0],
568 normal: [0.0, 0.0, 1.0],
569 tex_coords: [0.0, 0.0],
570 joint_indices: def_j,
571 joint_weights: def_w, ..Default::default()
572 },
573 Vertex {
574 position: [-hw, -hh, 0.0],
575 color: [1.0, 1.0, 1.0],
576 normal: [0.0, 0.0, 1.0],
577 tex_coords: [0.0, 1.0],
578 joint_indices: def_j,
579 joint_weights: def_w, ..Default::default()
580 },
581 ];
582
583 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
584 label: Some("Sprite Quad VBuf"),
585 contents: bytemuck::cast_slice(&vertices),
586 usage: wgpu::BufferUsages::VERTEX,
587 });
588
589 Mesh::new(
590 device,
591 Arc::new(vbuf),
592 &vertices,
593 Vec3::ZERO,
594 "sprite_quad".to_string(),
595 )
596 }
597
598 pub fn create_sphere(device: &wgpu::Device, radius: f32, stacks: u32, slices: u32) -> Mesh {
600 let stacks = stacks.max(3);
601 let slices = slices.max(3);
602 let mut vertices = Vec::new();
603 let pi = std::f32::consts::PI;
604
605 for i in 0..stacks {
606 let theta1 = (i as f32 / stacks as f32) * pi;
607 let theta2 = ((i + 1) as f32 / stacks as f32) * pi;
608
609 for j in 0..slices {
610 let phi1 = (j as f32 / slices as f32) * 2.0 * pi;
611 let phi2 = ((j + 1) as f32 / slices as f32) * 2.0 * pi;
612
613 let p1 = [
615 radius * theta1.sin() * phi1.cos(),
616 radius * theta1.cos(),
617 radius * theta1.sin() * phi1.sin(),
618 ];
619 let p2 = [
620 radius * theta2.sin() * phi1.cos(),
621 radius * theta2.cos(),
622 radius * theta2.sin() * phi1.sin(),
623 ];
624 let p3 = [
625 radius * theta2.sin() * phi2.cos(),
626 radius * theta2.cos(),
627 radius * theta2.sin() * phi2.sin(),
628 ];
629 let p4 = [
630 radius * theta1.sin() * phi2.cos(),
631 radius * theta1.cos(),
632 radius * theta1.sin() * phi2.sin(),
633 ];
634
635 let n1 = [
636 theta1.sin() * phi1.cos(),
637 theta1.cos(),
638 theta1.sin() * phi1.sin(),
639 ];
640 let n2 = [
641 theta2.sin() * phi1.cos(),
642 theta2.cos(),
643 theta2.sin() * phi1.sin(),
644 ];
645 let n3 = [
646 theta2.sin() * phi2.cos(),
647 theta2.cos(),
648 theta2.sin() * phi2.sin(),
649 ];
650 let n4 = [
651 theta1.sin() * phi2.cos(),
652 theta1.cos(),
653 theta1.sin() * phi2.sin(),
654 ];
655
656 let uv1 = [
657 if i == 0 {
658 (j as f32 + 0.5) / slices as f32
659 } else {
660 j as f32 / slices as f32
661 },
662 i as f32 / stacks as f32,
663 ];
664 let uv2 = [
665 if i + 1 == stacks {
666 (j as f32 + 0.5) / slices as f32
667 } else {
668 j as f32 / slices as f32
669 },
670 (i + 1) as f32 / stacks as f32,
671 ];
672 let uv3 = [
673 if i + 1 == stacks {
674 (j as f32 + 0.5) / slices as f32
675 } else {
676 (j + 1) as f32 / slices as f32
677 },
678 (i + 1) as f32 / stacks as f32,
679 ];
680 let uv4 = [
681 if i == 0 {
682 (j as f32 + 0.5) / slices as f32
683 } else {
684 (j + 1) as f32 / slices as f32
685 },
686 i as f32 / stacks as f32,
687 ];
688
689 let def_j = [0; 4];
690 let def_w = [0.0; 4];
691
692 vertices.push(Vertex {
694 position: p1,
695 color: [1.0; 3],
696 normal: n1,
697 tex_coords: uv1,
698 joint_indices: def_j,
699 joint_weights: def_w, ..Default::default()
700 });
701 vertices.push(Vertex {
702 position: p2,
703 color: [1.0; 3],
704 normal: n2,
705 tex_coords: uv2,
706 joint_indices: def_j,
707 joint_weights: def_w, ..Default::default()
708 });
709 vertices.push(Vertex {
710 position: p3,
711 color: [1.0; 3],
712 normal: n3,
713 tex_coords: uv3,
714 joint_indices: def_j,
715 joint_weights: def_w, ..Default::default()
716 });
717 vertices.push(Vertex {
719 position: p1,
720 color: [1.0; 3],
721 normal: n1,
722 tex_coords: uv1,
723 joint_indices: def_j,
724 joint_weights: def_w, ..Default::default()
725 });
726 vertices.push(Vertex {
727 position: p3,
728 color: [1.0; 3],
729 normal: n3,
730 tex_coords: uv3,
731 joint_indices: def_j,
732 joint_weights: def_w, ..Default::default()
733 });
734 vertices.push(Vertex {
735 position: p4,
736 color: [1.0; 3],
737 normal: n4,
738 tex_coords: uv4,
739 joint_indices: def_j,
740 joint_weights: def_w, ..Default::default()
741 });
742 }
743 }
744
745 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
746 label: Some("Sphere VBuf"),
747 contents: bytemuck::cast_slice(&vertices),
748 usage: wgpu::BufferUsages::VERTEX,
749 });
750
751 Mesh::new(
752 device,
753 Arc::new(vbuf),
754 &vertices,
755 Vec3::ZERO,
756 format!("sphere_{}_{}_{}", radius, stacks, slices),
757 )
758 }
759
760 pub fn create_cylinder(device: &wgpu::Device, radius: f32, height: f32, radial_segments: u32) -> Mesh {
761 let radial_segments = radial_segments.max(3);
762 let mut vertices = Vec::new();
763 let pi = std::f32::consts::PI;
764 let half_h = height / 2.0;
765
766 for i in 0..radial_segments {
768 let t1 = (i as f32 / radial_segments as f32) * 2.0 * pi;
769 let t2 = ((i + 1) as f32 / radial_segments as f32) * 2.0 * pi;
770
771 let u1 = i as f32 / radial_segments as f32;
772 let u2 = (i + 1) as f32 / radial_segments as f32;
773
774 let p1_top = [radius * t1.cos(), half_h, radius * t1.sin()];
775 let p1_bot = [radius * t1.cos(), -half_h, radius * t1.sin()];
776 let p2_top = [radius * t2.cos(), half_h, radius * t2.sin()];
777 let p2_bot = [radius * t2.cos(), -half_h, radius * t2.sin()];
778
779 let n1 = [t1.cos(), 0.0, t1.sin()];
780 let n2 = [t2.cos(), 0.0, t2.sin()];
781
782 let def_j = [0; 4]; let def_w = [0.0; 4];
783 let col = [1.0; 3];
784
785 vertices.push(Vertex { position: p1_top, normal: n1, tex_coords: [u1, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
787 vertices.push(Vertex { position: p1_bot, normal: n1, tex_coords: [u1, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
788 vertices.push(Vertex { position: p2_bot, normal: n2, tex_coords: [u2, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
789
790 vertices.push(Vertex { position: p1_top, normal: n1, tex_coords: [u1, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
792 vertices.push(Vertex { position: p2_bot, normal: n2, tex_coords: [u2, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
793 vertices.push(Vertex { position: p2_top, normal: n2, tex_coords: [u2, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
794
795 vertices.push(Vertex { position: [0.0, half_h, 0.0], normal: [0.0, 1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
797 vertices.push(Vertex { position: p1_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + 0.5 * t1.cos(), 0.5 + 0.5 * t1.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
798 vertices.push(Vertex { position: p2_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + 0.5 * t2.cos(), 0.5 + 0.5 * t2.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
799
800 vertices.push(Vertex { position: [0.0, -half_h, 0.0], normal: [0.0, -1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
802 vertices.push(Vertex { position: p2_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t2.cos(), 0.5 + 0.5 * t2.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
803 vertices.push(Vertex { position: p1_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t1.cos(), 0.5 + 0.5 * t1.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
804 }
805
806 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Cylinder VBuf"), contents: bytemuck::cast_slice(&vertices), usage: wgpu::BufferUsages::VERTEX });
807 Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, format!("cylinder_{}_{}", radius, height))
808 }
809
810 pub fn create_cone(device: &wgpu::Device, radius: f32, height: f32, radial_segments: u32) -> Mesh {
811 let radial_segments = radial_segments.max(3);
812 let mut vertices = Vec::new();
813 let pi = std::f32::consts::PI;
814 let half_h = height / 2.0;
815
816 let slant = (radius * radius + height * height).sqrt();
817 let ny = radius / slant;
818 let n_xz = height / slant;
819
820 for i in 0..radial_segments {
821 let t1 = (i as f32 / radial_segments as f32) * 2.0 * pi;
822 let t2 = ((i + 1) as f32 / radial_segments as f32) * 2.0 * pi;
823
824 let p1_bot = [radius * t1.cos(), -half_h, radius * t1.sin()];
825 let p2_bot = [radius * t2.cos(), -half_h, radius * t2.sin()];
826 let apex = [0.0, half_h, 0.0];
827
828 let n1 = [n_xz * t1.cos(), ny, n_xz * t1.sin()];
829 let n2 = [n_xz * t2.cos(), ny, n_xz * t2.sin()];
830 let navg = [n_xz * ((t1+t2)/2.0).cos(), ny, n_xz * ((t1+t2)/2.0).sin()];
831
832 let u1 = i as f32 / radial_segments as f32;
833 let u2 = (i + 1) as f32 / radial_segments as f32;
834 let umid = (u1 + u2) / 2.0;
835
836 let def_j = [0; 4]; let def_w = [0.0; 4];
837 let col = [1.0; 3];
838
839 vertices.push(Vertex { position: apex, normal: navg, tex_coords: [umid, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
841 vertices.push(Vertex { position: p1_bot, normal: n1, tex_coords: [u1, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
842 vertices.push(Vertex { position: p2_bot, normal: n2, tex_coords: [u2, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
843
844 vertices.push(Vertex { position: [0.0, -half_h, 0.0], normal: [0.0, -1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
846 vertices.push(Vertex { position: p2_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t2.cos(), 0.5 + 0.5 * t2.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
847 vertices.push(Vertex { position: p1_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t1.cos(), 0.5 + 0.5 * t1.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
848 }
849
850 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Cone VBuf"), contents: bytemuck::cast_slice(&vertices), usage: wgpu::BufferUsages::VERTEX });
851 Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, format!("cone_{}_{}", radius, height))
852 }
853
854 pub fn create_torus(device: &wgpu::Device, radius: f32, tube_radius: f32, radial_segments: u32, tubular_segments: u32) -> Mesh {
855 let radial_segments = radial_segments.max(3);
856 let tubular_segments = tubular_segments.max(3);
857 let mut vertices = Vec::new();
858 let pi = std::f32::consts::PI;
859
860 for i in 0..radial_segments {
861 for j in 0..tubular_segments {
862 let u1 = i as f32 / radial_segments as f32;
863 let u2 = (i + 1) as f32 / radial_segments as f32;
864 let v1 = j as f32 / tubular_segments as f32;
865 let v2 = (j + 1) as f32 / tubular_segments as f32;
866
867 let t1 = u1 * 2.0 * pi;
868 let t2 = u2 * 2.0 * pi;
869 let p1 = v1 * 2.0 * pi;
870 let p2 = v2 * 2.0 * pi;
871
872 let pos = |t: f32, p: f32| {
873 [(radius + tube_radius * p.cos()) * t.cos(), tube_radius * p.sin(), (radius + tube_radius * p.cos()) * t.sin()]
874 };
875 let norm = |t: f32, p: f32| {
876 [p.cos() * t.cos(), p.sin(), p.cos() * t.sin()]
877 };
878
879 let p_00 = pos(t1, p1); let n_00 = norm(t1, p1);
880 let p_10 = pos(t2, p1); let n_10 = norm(t2, p1);
881 let p_01 = pos(t1, p2); let n_01 = norm(t1, p2);
882 let p_11 = pos(t2, p2); let n_11 = norm(t2, p2);
883
884 let def_j = [0; 4]; let def_w = [0.0; 4];
885 let col = [1.0; 3];
886
887 vertices.push(Vertex { position: p_00, normal: n_00, tex_coords: [u1, v1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
888 vertices.push(Vertex { position: p_01, normal: n_01, tex_coords: [u1, v2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
889 vertices.push(Vertex { position: p_10, normal: n_10, tex_coords: [u2, v1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
890
891 vertices.push(Vertex { position: p_10, normal: n_10, tex_coords: [u2, v1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
892 vertices.push(Vertex { position: p_01, normal: n_01, tex_coords: [u1, v2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
893 vertices.push(Vertex { position: p_11, normal: n_11, tex_coords: [u2, v2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
894 }
895 }
896
897 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Torus VBuf"), contents: bytemuck::cast_slice(&vertices), usage: wgpu::BufferUsages::VERTEX });
898 Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, format!("torus_{}_{}", radius, tube_radius))
899 }
900
901 pub fn create_capsule(device: &wgpu::Device, radius: f32, depth: f32, latitudes: u32, longitudes: u32) -> Mesh {
902 let latitudes = latitudes.max(4);
903 let longitudes = longitudes.max(4);
904 let mut vertices = Vec::new();
905 let pi = std::f32::consts::PI;
906 let half_d = depth / 2.0;
907
908 for i in 0..=latitudes {
909 let u1 = i as f32 / latitudes as f32;
910 let u2 = (i + 1) as f32 / latitudes as f32;
911 let theta1 = u1 * pi;
912 let theta2 = u2 * pi;
913
914 let y_offset1 = if u1 < 0.5 { half_d } else if u1 > 0.5 { -half_d } else { 0.0 };
915 let y_offset2 = if u2 < 0.5 { half_d } else if u2 > 0.5 { -half_d } else { 0.0 };
916
917 let is_equator = i == latitudes / 2;
919
920 if is_equator {
921 for j in 0..longitudes {
923 let v1 = j as f32 / longitudes as f32;
924 let v2 = (j + 1) as f32 / longitudes as f32;
925 let phi1 = v1 * 2.0 * pi;
926 let phi2 = v2 * 2.0 * pi;
927
928 let p1_top = [radius * phi1.cos(), half_d, radius * phi1.sin()];
929 let p1_bot = [radius * phi1.cos(), -half_d, radius * phi1.sin()];
930 let p2_top = [radius * phi2.cos(), half_d, radius * phi2.sin()];
931 let p2_bot = [radius * phi2.cos(), -half_d, radius * phi2.sin()];
932
933 let n1 = [phi1.cos(), 0.0, phi1.sin()];
934 let n2 = [phi2.cos(), 0.0, phi2.sin()];
935
936 let def_j = [0; 4]; let def_w = [0.0; 4]; let col = [1.0; 3];
937
938 vertices.push(Vertex { position: p1_top, normal: n1, tex_coords: [v1, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
940 vertices.push(Vertex { position: p1_bot, normal: n1, tex_coords: [v1, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
941 vertices.push(Vertex { position: p2_bot, normal: n2, tex_coords: [v2, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
942
943 vertices.push(Vertex { position: p1_top, normal: n1, tex_coords: [v1, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
945 vertices.push(Vertex { position: p2_bot, normal: n2, tex_coords: [v2, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
946 vertices.push(Vertex { position: p2_top, normal: n2, tex_coords: [v2, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
947 }
948 }
949
950 if i < latitudes {
951 for j in 0..longitudes {
952 let v1 = j as f32 / longitudes as f32;
953 let v2 = (j + 1) as f32 / longitudes as f32;
954 let phi1 = v1 * 2.0 * pi;
955 let phi2 = v2 * 2.0 * pi;
956
957 let p1 = [radius * theta1.sin() * phi1.cos(), radius * theta1.cos() + y_offset1, radius * theta1.sin() * phi1.sin()];
958 let p2 = [radius * theta2.sin() * phi1.cos(), radius * theta2.cos() + y_offset2, radius * theta2.sin() * phi1.sin()];
959 let p3 = [radius * theta2.sin() * phi2.cos(), radius * theta2.cos() + y_offset2, radius * theta2.sin() * phi2.sin()];
960 let p4 = [radius * theta1.sin() * phi2.cos(), radius * theta1.cos() + y_offset1, radius * theta1.sin() * phi2.sin()];
961
962 let n1 = [theta1.sin() * phi1.cos(), theta1.cos(), theta1.sin() * phi1.sin()];
963 let n2 = [theta2.sin() * phi1.cos(), theta2.cos(), theta2.sin() * phi1.sin()];
964 let n3 = [theta2.sin() * phi2.cos(), theta2.cos(), theta2.sin() * phi2.sin()];
965 let n4 = [theta1.sin() * phi2.cos(), theta1.cos(), theta1.sin() * phi2.sin()];
966
967 let def_j = [0; 4]; let def_w = [0.0; 4]; let col = [1.0; 3];
968
969 vertices.push(Vertex { position: p1, normal: n1, tex_coords: [v1, u1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
971 vertices.push(Vertex { position: p2, normal: n2, tex_coords: [v1, u2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
972 vertices.push(Vertex { position: p3, normal: n3, tex_coords: [v2, u2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
973
974 vertices.push(Vertex { position: p1, normal: n1, tex_coords: [v1, u1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
976 vertices.push(Vertex { position: p3, normal: n3, tex_coords: [v2, u2], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
977 vertices.push(Vertex { position: p4, normal: n4, tex_coords: [v2, u1], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
978 }
979 }
980 }
981
982 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Capsule VBuf"), contents: bytemuck::cast_slice(&vertices), usage: wgpu::BufferUsages::VERTEX });
983 Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, format!("capsule_{}_{}", radius, depth))
984 }
985
986
987 pub fn create_terrain(
988 device: &wgpu::Device,
989 heightmap_path: &str,
990 width: f32,
991 depth: f32,
992 max_height: f32,
993 ) -> Result<(Mesh, Vec<f32>, u32, u32), String> {
994 let canonical = std::path::Path::new(heightmap_path)
995 .canonicalize()
996 .map(|p| p.to_string_lossy().to_string())
997 .unwrap_or_else(|_| heightmap_path.to_string());
998
999 let img = image::open(&canonical)
1000 .map_err(|e| format!("Heightmap yuklenemedi! {} ({})", canonical, e))?
1001 .into_luma8(); let (img_width, img_height) = img.dimensions();
1004 if img_width < 2 || img_height < 2 {
1005 return Err(
1006 "Heightmap boyutlari en az 2x2 olmalidir. 1x1 piksel ile arazi olusturulamaz."
1007 .to_string(),
1008 );
1009 }
1010 let mut vertices: Vec<Vertex> = Vec::with_capacity((img_width * img_height) as usize);
1013 let mut heights: Vec<f32> = Vec::with_capacity((img_width * img_height) as usize);
1014
1015 let half_w = width / 2.0;
1016 let half_d = depth / 2.0;
1017
1018 for y in 0..img_height {
1020 for x in 0..img_width {
1021 let pixel = img.get_pixel(x, y)[0] as f32 / 255.0; heights.push(pixel);
1023 let world_y = pixel * max_height;
1024
1025 let world_x = -half_w + (x as f32 / (img_width as f32 - 1.0)) * width;
1026 let world_z = -half_d + (y as f32 / (img_height as f32 - 1.0)) * depth;
1027
1028 let uv_x = (x as f32 / (img_width as f32 - 1.0)) * 10.0;
1030 let uv_y = (y as f32 / (img_height as f32 - 1.0)) * 10.0;
1031
1032 vertices.push(Vertex {
1033 position: [world_x, world_y, world_z],
1034 color: [1.0, 1.0, 1.0],
1035 normal: [0.0, 1.0, 0.0], tex_coords: [uv_x, uv_y],
1037 joint_indices: [0; 4],
1038 joint_weights: [0.0; 4], ..Default::default()
1039 });
1040 }
1041 }
1042
1043 let mut indices = Vec::with_capacity(((img_width - 1) * (img_height - 1) * 6) as usize);
1045 for y in 0..(img_height - 1) {
1046 for x in 0..(img_width - 1) {
1047 let i0 = y * img_width + x;
1048 let i1 = y * img_width + (x + 1);
1049 let i2 = (y + 1) * img_width + x;
1050 let i3 = (y + 1) * img_width + (x + 1);
1051
1052 indices.push(i0);
1054 indices.push(i2);
1055 indices.push(i1);
1056
1057 indices.push(i1);
1059 indices.push(i2);
1060 indices.push(i3);
1061 }
1062 }
1063
1064 let mut final_vertices = Vec::with_capacity(indices.len());
1066 for chunk in indices.chunks(3) {
1067 let i0 = chunk[0] as usize;
1068 let i1 = chunk[1] as usize;
1069 let i2 = chunk[2] as usize;
1070
1071 let p0 = Vec3::from_array(vertices[i0].position);
1072 let p1 = Vec3::from_array(vertices[i1].position);
1073 let p2 = Vec3::from_array(vertices[i2].position);
1074
1075 let norm = (p1 - p0).cross(p2 - p0);
1076 let normal = if norm.length_squared() > 1e-6 {
1077 norm.normalize()
1078 } else {
1079 Vec3::new(0.0, 1.0, 0.0)
1080 };
1081
1082 let mut v0 = vertices[i0];
1084 v0.normal = [normal.x, normal.y, normal.z];
1085 let mut v1 = vertices[i1];
1086 v1.normal = [normal.x, normal.y, normal.z];
1087 let mut v2 = vertices[i2];
1088 v2.normal = [normal.x, normal.y, normal.z];
1089
1090 final_vertices.push(v0);
1091 final_vertices.push(v1);
1092 final_vertices.push(v2);
1093 }
1094
1095 let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
1096 label: Some(&format!("Terrain ({})", heightmap_path)),
1097 contents: bytemuck::cast_slice(&final_vertices),
1098 usage: wgpu::BufferUsages::VERTEX,
1099 });
1100
1101 let mesh = Mesh::new(
1102 device,
1103 Arc::new(vbuf),
1104 &final_vertices,
1105 Vec3::ZERO,
1106 format!("terrain:{}", heightmap_path),
1107 );
1108 Ok((mesh, heights, img_width, img_height))
1109 }
1110}