obj_2_rust/
lib.rs

1use std::{env, path::Path};
2
3use mesh::Vertex;
4use proc_macro::TokenStream;
5use quote::quote;
6use read_file::read_lines;
7use syn::{LitStr, parse_macro_input};
8
9mod mesh;
10mod read_file;
11
12#[proc_macro]
13pub fn obj_2_rust(input: TokenStream) -> TokenStream {
14    let input = parse_macro_input!(input as LitStr);
15    let file_name = input.value();
16
17    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
18    let manifest_path = Path::new(&manifest_dir);
19    let file_path = manifest_path.with_file_name(file_name);
20    let lines = read_lines(file_path).unwrap();
21
22    let mut vertices: Vec<[f32; 3]> = Vec::new();
23    let mut normals: Vec<[f32; 3]> = Vec::new();
24    let mut uv_coords: Vec<[f32; 2]> = Vec::new();
25
26    let mut model_vertices: Vec<Vertex> = Vec::new();
27
28    let mut indices: Vec<u32> = Vec::new();
29
30    for line in lines.map_while(Result::ok) {
31        let line_split = line.split_whitespace().collect::<Vec<_>>();
32
33        if line_split.is_empty() {
34            continue;
35        }
36
37        match line_split[0] {
38            "o" => {
39                // TODO: implement
40            }
41            // Vertex position
42            "v" => {
43                vertices.push([
44                    line_split[1].parse::<f32>().unwrap(),
45                    line_split[2].parse::<f32>().unwrap(),
46                    line_split[3].parse::<f32>().unwrap(),
47                ]);
48            }
49            // UV Coordinate
50            "vt" => {
51                uv_coords.push([
52                    1.0 - line_split[1].parse::<f32>().unwrap(),
53                    1.0 - line_split[2].parse::<f32>().unwrap(),
54                ]);
55            }
56            // Normals
57            "vn" => {
58                normals.push([
59                    line_split[1].parse::<f32>().unwrap(),
60                    line_split[2].parse::<f32>().unwrap(),
61                    line_split[3].parse::<f32>().unwrap(),
62                ]);
63            }
64            // face
65            "f" => {
66                // Assuming triangulated
67                for vertex_info in line_split[1..3].iter() {
68                    let vertex_info_split = vertex_info.split('/').collect::<Vec<_>>();
69
70                    // Get the indices of each vertex, uv, and normal for the face
71                    let (vertex_index, uv_index, normal_index) = (
72                        vertex_info_split[0].parse::<usize>().unwrap() - 1,
73                        vertex_info_split[1].parse::<usize>().unwrap() - 1,
74                        vertex_info_split[2].parse::<usize>().unwrap() - 1,
75                    );
76
77                    model_vertices.push(Vertex {
78                        position: vertices[vertex_index],
79                        normal: normals[normal_index],
80                        uv: uv_coords[uv_index],
81                    });
82
83                    indices.push(model_vertices.len() as u32 - 1);
84                }
85            }
86            _ => {}
87        }
88    }
89
90    let vertex_tokens = model_vertices
91        .iter()
92        .map(|vertex| {
93            let position = &vertex.position;
94            let normal = &vertex.normal;
95            let uv = &vertex.uv;
96
97            quote! {
98                (#(#position),*, #(#normal),*, #(#uv),*)
99            }
100        })
101        .collect::<Vec<_>>();
102
103    let index_tokens = indices
104        .iter()
105        .map(|index| {
106            let model_index = &index;
107
108            quote! {
109                #model_index
110            }
111        })
112        .collect::<Vec<_>>();
113
114    let size = index_tokens.len();
115
116    let combined = quote! {
117        ([#(#vertex_tokens),*], [#(#index_tokens),*], #size)
118    };
119
120    combined.into()
121}