flow_ngin/resources/
mod.rs1use std::{
2 collections::HashMap,
3 convert::identity,
4 io::{BufReader, Cursor},
5};
6
7use crate::{
8 data_structures::{
9 model::{self},
10 scene_graph::{AnimationClip, ContainerNode, SceneNode, to_scene_node},
11 texture::Texture,
12 }, pick::PickId, resources::{
13 animation::Keyframes,
14 texture::{diffuse_normal_layout, load_binary, load_texture},
15 }
16};
17
18pub mod animation;
22pub mod mesh;
23pub mod pick;
24pub mod texture;
25
26pub async fn load_model_obj(
27 file_name: &str,
28 device: &wgpu::Device,
29 queue: &wgpu::Queue,
30) -> anyhow::Result<model::Model> {
31 let bind_group_layout = diffuse_normal_layout(device);
32
33 let (materials, models) =
34 texture::load_textures(file_name, queue, device, &bind_group_layout).await?;
35 let meshes = mesh::load_meshes(&models, file_name, device);
36 let meshes = meshes.into_iter().enumerate().filter_map(|(idx, result)| {
37 match result {
38 Ok(mesh) => Some(mesh),
39 Err(_) => {
40 log::warn!("Mesh at index {} in file {} could not be loaded due to overflows. Make sure you use the right scale in your .obj export settings.", idx, file_name);
41 None
42 },
43 }
44 }).collect();
45
46 let model = model::Model { meshes, materials };
47 Ok(model)
48}
49
50pub async fn load_model_gltf(
54 id: impl Into<PickId>,
55 file_name: &str,
56 device: &wgpu::Device,
57 queue: &wgpu::Queue,
58) -> anyhow::Result<Box<dyn SceneNode + Send>> {
59 let gltf_text = load_binary(file_name).await?;
60 let gltf_cursor = Cursor::new(gltf_text);
61 let gltf_reader = BufReader::new(gltf_cursor);
62 let gltf = gltf::Gltf::from_reader(gltf_reader)?;
63
64 let mut buffer_data = Vec::new();
66 for buffer in gltf.buffers() {
67 match buffer.source() {
68 gltf::buffer::Source::Bin => {
69 if let Some(blob) = gltf.blob.as_deref() {
70 buffer_data.push(blob.into());
71 };
72 }
73 gltf::buffer::Source::Uri(uri) => {
74 let bin = load_binary(uri).await?;
75 buffer_data.push(bin);
76 }
77 }
78 }
79 let mut animations: HashMap<usize, Vec<AnimationClip>> = HashMap::new();
81 for animation in gltf.animations() {
82 for channel in animation.channels() {
83 let reader = channel.reader(|buffer| Some(&buffer_data[buffer.index()]));
84 let timestamps = if let Some(inputs) = reader.read_inputs() {
85 match inputs {
86 gltf::accessor::Iter::Standard(times) => {
87 let times: Vec<f32> = times.collect();
88 times
89 }
90 gltf::accessor::Iter::Sparse(_) => {
91 let times: Vec<f32> = Vec::new();
92 times
93 }
94 }
95 } else {
96 log::warn!("No animation found in channel {}", channel.index());
97 let times: Vec<f32> = Vec::new();
98 times
99 };
100 let keyframes = if let Some(outputs) = reader.read_outputs() {
101 match outputs {
102 gltf::animation::util::ReadOutputs::Translations(translation) => {
103 let translation_vec = translation
104 .map(|tr| {
105 let vector = tr.into();
106 vector
107 })
108 .collect();
109 Keyframes::Translation(translation_vec)
110 }
111 gltf::animation::util::ReadOutputs::Rotations(rotation) => {
112 let quaternions: Vec<cgmath::Quaternion<f32>> = rotation
113 .into_f32()
114 .map(|quat| {
115 let quat = quat.into();
116 quat
117 })
118 .collect();
119 Keyframes::Rotation(quaternions)
120 }
121 gltf::animation::util::ReadOutputs::Scales(scales) => {
122 let quaternion = scales
123 .map(|sc| {
124 let sc = sc.into();
125 sc
126 })
127 .collect();
128 Keyframes::Scale(quaternion)
129 }
130 gltf::animation::util::ReadOutputs::MorphTargetWeights(_) => Keyframes::Other,
132 }
133 } else {
134 log::warn!("No Keyframes found in channel {}", channel.index());
135 Keyframes::Other
136 };
137 let name = animation.name().unwrap_or("Default").to_string();
138 let animation = AnimationClip {
139 name,
140 keyframes,
141 timestamps,
142 };
143 animations
144 .entry(channel.target().node().index())
145 .and_modify(|v| v.push(animation.clone()))
146 .or_insert(vec![animation]);
147 }
148 }
149 let mut materials = Vec::new();
151 for material in gltf.materials() {
152 let pbr = material.pbr_metallic_roughness();
153 let texture_source = &pbr
154 .base_color_texture()
155 .map(|tex| tex.texture().source().source())
156 .expect("texture");
157 let diffuse_texture = match texture_source {
158 gltf::image::Source::View { view, mime_type } => {
159 let diffuse_texture = Texture::from_bytes(
160 device,
161 queue,
162 &buffer_data[view.buffer().index()],
163 file_name,
164 mime_type.split('/').last(),
165 false,
166 )
167 .expect("Couldn't load diffuse");
168 diffuse_texture
169 }
170 gltf::image::Source::Uri { uri, mime_type } => {
171 let diffuse_texture = load_texture(
172 uri,
173 false,
174 device,
175 queue,
176 mime_type.map(|mt| mt.split('/').last().map_or("jpg", identity)),
177 )
178 .await?;
179 diffuse_texture
180 }
181 };
182 let normal_texture = if let Some(texture) = material.normal_texture() {
183 match &texture.texture().source().source() {
195 gltf::image::Source::View { view, mime_type: _ } => {
196 let texture = Texture::from_bytes(
197 device,
198 queue,
199 &buffer_data[view.buffer().index()],
200 file_name,
201 None,
202 true,
203 )
204 .expect("Couldn't load normal");
205 texture
206 }
207 gltf::image::Source::Uri { uri, mime_type: _ } => {
209 let texture = load_texture(uri, true, device, queue, None).await?;
210 texture
211 }
212 }
213 } else {
214 Texture::create_default_normal_map(2, 2, device, queue)
215 };
216 let name = format!("{}.gltf", file_name);
217 let name = name.as_str();
218 let layout = &diffuse_normal_layout(device);
219 if let Ok(material) =
220 model::Material::new(device, name, diffuse_texture, normal_texture, layout)
221 {
222 materials.push(material);
223 } else {
224 log::warn!("Failed to create material for gltf ({})", file_name);
225 }
226 }
227
228 let mut models = Vec::new();
229
230 let id = id.into();
231 for scene in gltf.scenes() {
232 for node in scene.nodes() {
233 let model = to_scene_node(id, node, &buffer_data, device, &materials, &animations);
234 models.push(model);
235 }
236 }
237
238 let mut root_node = if models.len() == 1 {
239 models.into_iter().next().unwrap()
240 } else {
241 let mut root_node = ContainerNode::new(1, Vec::new());
242 root_node.children = models;
243 Box::new(root_node)
244 };
245 root_node.update_world_transform_all();
246
247 Ok(root_node)
248}