use glam::Quat;
use gltf::json::{accessor::ComponentType, validation::Checked};
use thiserror::Error;
use tracing::{debug, error, warn};
use crate::{
document::GltfDocument,
graph::gltf::{
accessor::Accessor,
buffer::Buffer,
buffer_view::{BufferView, Target},
mesh::Mesh,
node::Node,
primitive::Primitive,
scene::Scene,
},
io::resolver::Resolver,
};
use super::GltfFormat;
#[derive(Debug, Error)]
pub enum GltfImportError {}
impl GltfFormat {
pub async fn import(
mut self,
mut resolver: Option<&mut impl Resolver>,
) -> Result<GltfDocument, GltfImportError> {
let mut doc = GltfDocument::default();
let mut buffers = Vec::new();
for b in self.json.buffers.iter_mut() {
let mut buffer = Buffer::new(&mut doc.0);
let weight = buffer.get_mut(&mut doc.0);
weight.name = b.name.take();
weight.extras = b.extras.take();
weight.byte_length = b.byte_length.0 as usize;
weight.uri = b.uri.take();
if let Some(uri) = weight.uri.as_ref() {
if let Some(resolver) = resolver.as_mut() {
if let Ok(blob) = resolver.resolve(uri).await {
debug!("Resolved buffer: {} ({} bytes)", uri, blob.len());
weight.blob = Some(blob);
} else {
warn!("Failed to resolve URI: {}", uri);
}
} else {
warn!("No resolver provided");
}
} else if self.resources.len() == 1 {
let key = self
.resources
.iter_mut()
.find(|_| true)
.map(|(k, _)| k.clone())
.unwrap();
weight.blob = self.resources.remove(&key);
}
buffers.push(buffer);
}
let buffer_views = self
.json
.buffer_views
.iter_mut()
.map(|v| {
let mut view = BufferView::new(&mut doc.0);
let weight = view.get_mut(&mut doc.0);
weight.name = v.name.take();
weight.extras = v.extras.take();
weight.byte_length = v.byte_length.0 as usize;
weight.byte_offset = v.byte_offset.map(|o| o.0).unwrap_or_default() as usize;
weight.byte_stride = v.byte_stride.map(|s| s.0);
weight.target = v.target.and_then(|t| match t {
Checked::Valid(target) => Some(match target {
gltf::json::buffer::Target::ArrayBuffer => Target::ArrayBuffer,
gltf::json::buffer::Target::ElementArrayBuffer => {
Target::ElementArrayBuffer
}
}),
Checked::Invalid => None,
});
if let Some(buffer) = buffers.get(v.buffer.value()) {
view.set_buffer(&mut doc.0, Some(buffer));
}
view
})
.collect::<Vec<_>>();
let accessors = self
.json
.accessors
.iter_mut()
.map(|a| {
let mut accessor = Accessor::new(&mut doc.0);
let weight = accessor.get_mut(&mut doc.0);
weight.name = a.name.take();
weight.extras = a.extras.take();
weight.byte_offset = a.byte_offset.map(|o| o.0).unwrap_or_default() as usize;
weight.count = a.count.0 as usize;
weight.normalized = a.normalized;
weight.component_type = match a.component_type {
Checked::Valid(component_type) => component_type.0,
Checked::Invalid => {
error!("Invalid accessor component type: {:?}", a.component_type);
ComponentType::U8
}
};
weight.element_type = match a.type_ {
Checked::Valid(ty) => ty,
Checked::Invalid => {
error!("Invalid accessor type: {:?}", a.type_);
gltf::json::accessor::Type::Scalar
}
};
if let Some(index) = a.buffer_view {
if let Some(buffer_view) = buffer_views.get(index.value()) {
accessor.set_buffer_view(&mut doc.0, Some(buffer_view));
}
}
accessor
})
.collect::<Vec<_>>();
let meshes = self
.json
.meshes
.iter_mut()
.map(|m| {
let mut mesh = Mesh::new(&mut doc.0);
let weight = mesh.get_mut(&mut doc.0);
weight.name = m.name.take();
weight.extras = m.extras.take();
m.primitives.iter_mut().for_each(|p| {
let mut primitive = Primitive::new(&mut doc.0);
let p_weight = primitive.get_mut(&mut doc.0);
p_weight.extras = p.extras.take();
p_weight.mode = match p.mode {
Checked::Valid(mode) => mode,
Checked::Invalid => gltf::mesh::Mode::Triangles,
};
if let Some(index) = p.indices {
if let Some(accessor) = accessors.get(index.value()) {
primitive.set_indices(&mut doc.0, Some(accessor));
}
}
p.attributes.iter().for_each(|(k, v)| {
if let Some(accessor) = accessors.get(v.value()) {
let semantic = match k {
Checked::Valid(semantic) => semantic,
Checked::Invalid => {
warn!("Invalid attribute semantic: {:?}", k);
return;
}
};
primitive.set_attribute(&mut doc.0, semantic, Some(accessor));
}
});
mesh.add_primitive(&mut doc.0, &primitive);
});
mesh
})
.collect::<Vec<_>>();
let nodes = self
.json
.nodes
.iter_mut()
.map(|n| {
let mut node = Node::new(&mut doc.0);
let weight = node.get_mut(&mut doc.0);
weight.name = n.name.take();
weight.extras = n.extras.take();
weight.translation = n.translation.map(|t| t.into()).unwrap_or_default();
weight.rotation = n
.rotation
.map(|r| Quat::from_slice(&r.0))
.unwrap_or(Quat::IDENTITY);
weight.scale = n.scale.map(|s| s.into()).unwrap_or(glam::Vec3::ONE);
if let Some(index) = n.mesh {
if let Some(mesh) = meshes.get(index.value()) {
node.set_mesh(&mut doc.0, Some(mesh));
}
}
node
})
.collect::<Vec<_>>();
self.json
.nodes
.iter()
.enumerate()
.filter_map(|(i, n)| n.children.as_ref().map(|c| (i, c)))
.for_each(|(i, children)| {
let node = &nodes[i];
children.iter().for_each(|idx| {
let child = &nodes[idx.value()];
node.add_child(&mut doc.0, child);
});
});
let scenes = self
.json
.scenes
.iter_mut()
.map(|s| {
let mut scene = Scene::new(&mut doc.0);
let weight = scene.get_mut(&mut doc.0);
weight.name = s.name.take();
weight.extras = s.extras.take();
s.nodes.iter().for_each(|idx| {
if let Some(node) = nodes.get(idx.value()) {
scene.add_node(&mut doc.0, node);
}
});
scene
})
.collect::<Vec<_>>();
if let Some(index) = self.json.scene {
if let Some(scene) = scenes.get(index.value()) {
doc.set_default_scene(Some(scene));
}
}
Ok(doc)
}
}