feo_oop_engine/components/
triangle_mesh.rs

1//! Mesh that has a material
2//! 
3//! TODO
4//! 
5use vulkano::sync;
6
7use {
8    super::{material::Material, texture::Texture},
9    crate::{
10        shaders::fs_draw,
11        components::{Normal, TextureIndex, Vertex}
12    },
13    std::{
14        sync::Arc,
15        collections::HashMap
16    },
17    vulkano::{
18        buffer::{
19            BufferUsage, 
20            CpuAccessibleBuffer
21        }, 
22        device::Queue,
23        sync::GpuFuture
24    }
25};
26
27/// The visible mesh made up of triangles belonging to a gameobject.
28#[derive(Clone)]
29pub struct TriangleMesh {
30    pub(crate) vertex_buffer: Option<Arc<CpuAccessibleBuffer<[Vertex]>>>, // make into buffer
31    pub(crate) normal_buffer: Option<Arc<CpuAccessibleBuffer<[Normal]>>>,
32    pub(crate) texture_indices_buffer: Option<Arc<CpuAccessibleBuffer<[TextureIndex]>>>,
33    
34    pub(crate) material: Option<(fs_draw::ty::Material, [Arc<Texture>; 4])>,
35}
36
37impl std::fmt::Debug for TriangleMesh {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "TriangleMesh debug todo")
40    }
41}
42
43impl TriangleMesh{
44    /// Create a new empty TriangleMesh
45    pub fn new_empty() -> Self{
46        TriangleMesh {
47            vertex_buffer: None,
48            normal_buffer: None,
49            texture_indices_buffer: None,
50            material: None,
51        }
52    }
53
54    /// Create a new TriangleMesh
55    pub fn new(
56            ordered_vertices: Vec<Vertex>,
57            ordered_normals: Vec<Normal>,
58            ordered_texture_indices: Vec<TextureIndex>,
59            material: Arc<Material>,
60            
61            queue: Arc<Queue>) -> Self {
62
63        TriangleMesh{
64            vertex_buffer: Some(CpuAccessibleBuffer::from_iter(queue.device().clone(), BufferUsage::all(), false, ordered_vertices.iter().cloned()).unwrap()),
65            normal_buffer: Some(CpuAccessibleBuffer::from_iter(queue.device().clone(), BufferUsage::all(), false, ordered_normals.iter().cloned()).unwrap()),
66            texture_indices_buffer: Some(CpuAccessibleBuffer::from_iter(queue.device().clone(), BufferUsage::all(), false, ordered_texture_indices.iter().cloned()).unwrap()),
67            material: Some(material.into_set(queue.clone())),
68        }
69    }
70
71    /// Create a triangle mesh from a section of an obj file.
72    #[allow(clippy::type_complexity)]
73    pub fn from_obj_block<'a>(block: &[&str], mtls_hashmap: &mut HashMap<String, (Arc<Material>, Box<dyn GpuFuture>)>, vertex_data: (&Vec<Box<Vertex>>, &Vec<Box<TextureIndex>>, &Vec<Box<Normal>>), queue: Arc<Queue>) -> Result<Self, &'a str> {
74        // Ordered mesh data
75        let mut ordered_vertices = Vec::new();
76        let mut ordered_normals = Vec::new();
77        let mut ordered_texture_indices = Vec::new();
78
79        let mut current_material: Arc<Material> = Arc::new(Material::default());
80        
81        block.iter().for_each(|line| {
82            if !(*line).is_empty() {
83                let mut e = line.split_whitespace();
84                let ty: &str = e.next().unwrap();
85                match &*ty {
86
87                    //   Faces   //
88
89                    "f" => {
90                        let mut tris = Vec::new();
91                        let mut i = 0;
92                        for coord in &mut e{
93                            i += 1;
94                            if i > 3{ // not perfect but good enough for now
95                                tris.push(tris[0]);
96                                tris.push(tris[i - 2]);
97                            }
98                            tris.push(coord);
99                        }
100
101                        let mut vertex_fmt: i8 = -1;
102                        let mut developing_normal: Vec<Vertex> = Vec::new();
103                        for raw in tris{
104                            let part = raw.split('/').collect::<Vec<&str>>();
105                            
106                            if vertex_fmt != part.len() as i8 {
107                                if vertex_fmt == -1 {
108                                    vertex_fmt = part.len() as i8;
109                                }else {
110                                    panic! ("Inconsistent face vertex format.")
111                                }
112                            }
113                            
114                            let position = *vertex_data.0[part[0].parse::<usize>().unwrap() - 1_usize].clone();
115
116                            let texture_index = if vertex_fmt > 1 && !part[1].is_empty() {
117                                    *vertex_data.1[part[1].parse::<usize>().unwrap() - 1_usize].clone()
118                                } else {
119                                    TextureIndex::new(0.0, 0.0)
120                                };
121
122                            if developing_normal.is_empty() && vertex_fmt == 3 && !part[2].is_empty() { // a false second case is a result of improper formatting
123                                ordered_normals.push(*vertex_data.2[part[2].parse::<usize>().unwrap() - 1_usize].clone());
124                            } else {
125                                developing_normal.push(position);
126                            }
127
128                            ordered_vertices.push(position);
129                            ordered_texture_indices.push(texture_index);
130                        }
131
132                        if developing_normal.len() > 2 {
133                            let normal = Normal::calculate_normal(&developing_normal[0], &developing_normal[1], developing_normal.last().unwrap());
134
135                            for _ in 0..developing_normal.len() {
136                                ordered_normals.push(normal);
137                            }
138                        }
139                    },
140                    
141                    //   Materials   //
142
143                    "usemtl" => {
144                        let key = e.next().expect("formatting error");
145                        let (cm, fut ) = mtls_hashmap.remove(key).unwrap();
146                        current_material = cm.clone();
147                        if fut.queue().is_some() {
148                            let _ = Arc::new(fut.then_signal_fence_and_flush().unwrap()).wait(None); // for now state does not matter                            
149                        }
150                        mtls_hashmap.insert(key.to_string(), (cm, sync::now(queue.device().clone()).boxed()));
151                    },
152
153                    //   Other   //
154
155                    &_ => {
156                        panic!("Formatting error"); 
157                    }
158                    
159                    //   TODO: Other Geometry   //
160
161                    #[allow(unreachable_patterns)] // fr now just ignore it TODO: fix
162
163                    "line" => {
164                        todo!();
165                    },
166                };
167            }
168            
169        });
170
171        Ok(Self::new(ordered_vertices, ordered_normals, ordered_texture_indices, current_material, queue))
172    }
173}