Skip to main content

gizmo_renderer/components/
mesh.rs

1use gizmo_math::Vec3;
2use std::sync::Arc;
3use wgpu::util::DeviceExt;
4
5#[derive(Clone)]
6pub struct Mesh {
7    pub vbuf: Arc<wgpu::Buffer>,
8    pub vertex_count: u32,
9    /// Geometrinin ağırlık merkezini orijine taşımak için kullanılan ofset değeri.
10    /// Render aşamasında model matrisine uygulanabilir.
11    /// AABB sınırlarını doğrudan etkilemez (sınırlar ham vertex verisinden hesaplanır).
12    pub center_offset: Vec3,
13    pub source: String,
14    pub bounds: gizmo_math::Aabb,
15    pub cpu_vertices: Arc<Vec<Vec3>>,
16    pub lod_vbufs: Vec<Arc<wgpu::Buffer>>,
17    pub lod_vertex_counts: Vec<u32>,
18}
19
20impl Mesh {
21    /// Yeni bir `Mesh` bileşeni oluşturur.
22    /// `vertices` dizisi üzerinden otomatik olarak `vertex_count` ve `bounds` hesaplanır.
23    /// Hata durumlarında boş bir mesh oluşturmak için `Mesh::empty()` kullanılmalıdır.
24    pub fn new(
25        device: &wgpu::Device,
26        vbuf: Arc<wgpu::Buffer>,
27        vertices: &[crate::gpu_types::Vertex],
28        center_offset: Vec3,
29        source: String,
30    ) -> Self {
31        debug_assert!(
32            !vertices.is_empty(),
33            "Kullanım hatası: Normal kullanımlarda vertices boş olamaz. Boş (fallback) mesh için Mesh::empty() kullanın."
34        );
35        let vertex_count = vertices.len() as u32;
36        debug_assert_eq!(
37            vertex_count as usize * std::mem::size_of::<crate::gpu_types::Vertex>(),
38            vbuf.size() as usize
39        );
40        let bounds = gizmo_math::Aabb::from_points(vertices.iter().map(|v| v.position));
41        let cpu_vertices = Arc::new(vertices.iter().map(|v| Vec3::from(v.position)).collect());
42
43        let mut lod_vbufs = Vec::new();
44        let mut lod_vertex_counts = Vec::new();
45
46        // 1. Un-indexed vertex array üzerinden index array oluştur (meshopt için gereklidir)
47        #[cfg(not(target_arch = "wasm32"))]
48        if vertex_count > 20000 {
49            let (unique_count, indices) = meshopt::generate_vertex_remap(vertices, None);
50
51            let mut unique_vertices = vec![crate::gpu_types::Vertex::default(); unique_count];
52            for (i, &new_idx) in indices.iter().enumerate() {
53                unique_vertices[new_idx as usize] = vertices[i];
54            }
55
56            let adapter = meshopt::VertexDataAdapter::new(
57                bytemuck::cast_slice(&unique_vertices),
58                std::mem::size_of::<crate::gpu_types::Vertex>(),
59                0,
60            )
61            .unwrap();
62
63            let target_count = (indices.len() as f32 * 0.5) as usize; // %50 decimation
64            let lod1_indices = meshopt::simplify(
65                &indices,
66                &adapter,
67                target_count,
68                0.1, // %10 error tolerance
69                meshopt::SimplifyOptions::empty(),
70                None,
71            );
72
73            // Eğer başarıyla decimation yapıldıysa ve gerçekten vertex sayısı düştüyse GPU'ya at
74            if !lod1_indices.is_empty() && lod1_indices.len() < indices.len() {
75                // Flat vertex array'e geri döndür (Gizmo renderer flat bekliyor)
76                let mut lod_flat = Vec::with_capacity(lod1_indices.len());
77                for &idx in &lod1_indices {
78                    lod_flat.push(unique_vertices[idx as usize]);
79                }
80
81                let lod_vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
82                    label: Some(&format!("LOD1 VBuf: {}", source)),
83                    contents: bytemuck::cast_slice(&lod_flat),
84                    usage: wgpu::BufferUsages::VERTEX,
85                });
86
87                lod_vbufs.push(Arc::new(lod_vbuf));
88                lod_vertex_counts.push(lod_flat.len() as u32);
89            }
90        }
91
92        Self {
93            vbuf,
94            vertex_count,
95            center_offset,
96            source,
97            bounds,
98            cpu_vertices,
99            lod_vbufs,
100            lod_vertex_counts,
101        }
102    }
103
104    /// Dosya yüklenememesi gibi durumlarda motorun çökmemesi için
105    /// 0 vertex'li, boş bir yer tutucu (fallback) Mesh oluşturur.
106    pub fn empty(vbuf: Arc<wgpu::Buffer>, source: String) -> Self {
107        Self {
108            vbuf,
109            vertex_count: 0,
110            center_offset: Vec3::ZERO,
111            source,
112            bounds: gizmo_math::Aabb::empty(),
113            cpu_vertices: Arc::new(Vec::new()),
114            lod_vbufs: Vec::new(),
115            lod_vertex_counts: Vec::new(),
116        }
117    }
118}
119
120/// Bir entity'nin ekrana çizilebilir bir Mesh olduğunu belirten ECS marker bileşenidir.
121/// Hiçbir ek alan içermez; sadece entity'nin render sistemine dahil edilmesini sağlar.
122#[derive(Clone)]
123pub struct MeshRenderer;
124
125impl MeshRenderer {
126    pub fn new() -> Self {
127        Self
128    }
129}
130
131impl Default for MeshRenderer {
132    fn default() -> Self {
133        Self::new()
134    }
135}