use gltf_json as json;
use gltf_json::buffer::Stride;
use json::validation::Checked::Valid;
use std::io::Write;
use std::path::Path;
use std::{fs, mem};
use tracing::info;
fn to_padded_byte_vector<T>(vec: Vec<T>) -> Vec<u8> {
let byte_length = vec.len() * mem::size_of::<T>();
let byte_capacity = vec.capacity() * mem::size_of::<T>();
let alloc = vec.into_boxed_slice();
let ptr = Box::<[T]>::into_raw(alloc) as *mut u8;
let mut new_vec = unsafe { Vec::from_raw_parts(ptr, byte_length, byte_capacity) };
while new_vec.len() % 4 != 0 {
new_vec.push(0); }
new_vec
}
pub fn write_gltf_file(triangle_mesh: egraphics_core::TriangleMesh, gltf_path: impl AsRef<Path>) {
assert!(!triangle_mesh.is_empty(), "No triangles found");
let bin_path = gltf_path.as_ref().with_extension("bin");
let bin_filename = bin_path.file_name().unwrap().to_str().unwrap().to_string();
let triangle_vertices = triangle_mesh.all_vertices();
let position_min = triangle_mesh.get_min();
let position_max = triangle_mesh.get_max();
let buffer_length = triangle_vertices.len() * mem::size_of::<egraphics_core::Vertex>();
let buffer = json::Buffer {
byte_length: buffer_length.into(),
extensions: Default::default(),
extras: Default::default(),
name: None,
uri: Some(bin_filename),
};
let buffer_view = json::buffer::View {
buffer: json::Index::new(0),
byte_length: buffer.byte_length,
byte_offset: None,
byte_stride: Some(Stride(mem::size_of::<egraphics_core::Vertex>())),
extensions: Default::default(),
extras: Default::default(),
name: None,
target: Some(Valid(json::buffer::Target::ArrayBuffer)),
};
let positions = json::Accessor {
buffer_view: Some(json::Index::new(0)),
byte_offset: None,
count: triangle_vertices.len().into(),
component_type: Valid(json::accessor::GenericComponentType(
json::accessor::ComponentType::F32,
)),
extensions: Default::default(),
extras: Default::default(),
type_: Valid(json::accessor::Type::Vec3),
min: Some(json::Value::from(vec![
position_min.x,
position_min.y,
position_min.z,
])),
max: Some(json::Value::from(vec![
position_max.x,
position_max.y,
position_max.z,
])),
name: None,
normalized: false,
sparse: None,
};
let colors = json::Accessor {
buffer_view: Some(json::Index::new(0)),
byte_offset: Some((3 * mem::size_of::<f32>()).into()),
count: triangle_vertices.len().into(),
component_type: Valid(json::accessor::GenericComponentType(
json::accessor::ComponentType::F32,
)),
extensions: Default::default(),
extras: Default::default(),
type_: Valid(json::accessor::Type::Vec3),
min: None,
max: None,
name: None,
normalized: false,
sparse: None,
};
let primitive = json::mesh::Primitive {
attributes: {
let mut map = std::collections::BTreeMap::new();
map.insert(Valid(json::mesh::Semantic::Positions), json::Index::new(0));
map.insert(Valid(json::mesh::Semantic::Colors(0)), json::Index::new(1));
map
},
extensions: Default::default(),
extras: Default::default(),
indices: None,
material: None,
mode: Valid(json::mesh::Mode::Triangles),
targets: None,
};
let mesh = json::Mesh {
extensions: Default::default(),
extras: Default::default(),
name: None,
primitives: vec![primitive],
weights: None,
};
let node = json::Node {
camera: None,
children: None,
extensions: Default::default(),
extras: Default::default(),
matrix: None,
mesh: Some(json::Index::new(0)),
name: None,
rotation: None,
scale: None,
translation: None,
skin: None,
weights: None,
};
let root = json::Root {
accessors: vec![positions, colors],
buffers: vec![buffer],
buffer_views: vec![buffer_view],
meshes: vec![mesh],
nodes: vec![node],
scenes: vec![json::Scene {
extensions: Default::default(),
extras: Default::default(),
name: None,
nodes: vec![json::Index::new(0)],
}],
..Default::default()
};
info!("Write to {:?}", gltf_path.as_ref());
let writer = fs::File::create(gltf_path).expect("I/O error");
json::serialize::to_writer_pretty(writer, &root).expect("Serialization error");
let bin = to_padded_byte_vector(triangle_vertices);
let mut writer = fs::File::create(bin_path).expect("I/O error");
writer.write_all(&bin).expect("I/O error");
}