use std::collections::HashMap;
use std::path::PathBuf;
pub const CELL_SENTINEL: u32 = u32::MAX;
pub const MAX_JOINTS: usize = 256;
#[derive(Clone, Debug)]
pub struct RasterImageData {
pub width: u32,
pub height: u32,
pub rgba: Vec<u8>,
}
#[derive(Clone, Debug)]
pub struct HdrImageData {
pub width: u32,
pub height: u32,
pub rgba: Vec<f32>,
}
#[derive(Clone, Debug)]
pub enum TextureSource {
File(PathBuf),
Decoded(RasterImageData),
}
#[derive(Clone, Debug)]
pub struct MaterialData {
pub name: String,
pub base_color: [f32; 3],
pub metallic: f32,
pub roughness: f32,
pub opacity: f32,
pub base_color_texture: Option<TextureSource>,
pub normal_map_texture: Option<TextureSource>,
pub ao_texture: Option<TextureSource>,
}
impl Default for MaterialData {
fn default() -> Self {
Self {
name: String::new(),
base_color: [0.7, 0.7, 0.7],
metallic: 0.0,
roughness: 0.5,
opacity: 1.0,
base_color_texture: None,
normal_map_texture: None,
ao_texture: None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AttributeDomain {
Point,
Cell,
Face,
Edge,
Halfedge,
Corner,
}
#[derive(Clone, Debug)]
pub enum AttributeValues {
Scalars(Vec<f32>),
Colors(Vec<[f32; 4]>),
Vectors(Vec<[f32; 3]>),
}
#[derive(Clone, Debug)]
pub struct AttributeData {
pub domain: AttributeDomain,
pub values: AttributeValues,
}
impl AttributeData {
pub fn scalars(domain: AttributeDomain, values: Vec<f32>) -> Self {
Self {
domain,
values: AttributeValues::Scalars(values),
}
}
pub fn colors(domain: AttributeDomain, values: Vec<[f32; 4]>) -> Self {
Self {
domain,
values: AttributeValues::Colors(values),
}
}
pub fn vectors(domain: AttributeDomain, values: Vec<[f32; 3]>) -> Self {
Self {
domain,
values: AttributeValues::Vectors(values),
}
}
}
#[derive(Clone, Debug)]
pub struct SkinWeights {
pub joint_indices: Vec<[u8; 4]>,
pub joint_weights: Vec<[f32; 4]>,
}
#[derive(Clone, Debug)]
pub struct Joint {
pub name: String,
pub parent: Option<u8>,
pub inverse_bind: glam::Mat4,
}
#[derive(Clone, Debug, Default)]
pub struct Skeleton {
pub name: String,
pub joints: Vec<Joint>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AnimationChannel {
Translation,
Rotation,
Scale,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AnimationInterpolation {
Step,
Linear,
CubicSpline,
}
#[derive(Clone, Debug)]
pub enum AnimationTrackValues {
Vec3(Vec<glam::Vec3>),
Quat(Vec<glam::Quat>),
}
#[derive(Clone, Debug)]
pub struct AnimationSampler {
pub interpolation: AnimationInterpolation,
pub times: Vec<f32>,
pub values: AnimationTrackValues,
}
#[derive(Clone, Debug)]
pub struct AnimationTrack {
pub joint: usize,
pub channel: AnimationChannel,
pub sampler: AnimationSampler,
}
#[derive(Clone, Debug)]
pub struct AnimationClip {
pub name: String,
pub duration: f32,
pub skeleton_index: usize,
pub tracks: Vec<AnimationTrack>,
}
#[derive(Clone, Debug, Default)]
pub struct SurfaceMesh {
pub positions: Vec<[f32; 3]>,
pub normals: Vec<[f32; 3]>,
pub indices: Vec<u32>,
pub uvs: Option<Vec<[f32; 2]>>,
pub tangents: Option<Vec<[f32; 4]>>,
pub attributes: HashMap<String, AttributeData>,
pub skin_weights: Option<SkinWeights>,
}
#[derive(Clone, Debug)]
pub struct SceneMesh {
pub name: String,
pub mesh: SurfaceMesh,
pub material_index: Option<usize>,
pub transform: glam::Mat4,
pub two_sided: bool,
pub parent_index: Option<usize>,
pub vertex_attribute_names: Vec<String>,
pub metadata: HashMap<String, String>,
pub skeleton_index: Option<usize>,
}
impl Default for SceneMesh {
fn default() -> Self {
Self {
name: String::new(),
mesh: SurfaceMesh::default(),
material_index: None,
transform: glam::Mat4::IDENTITY,
two_sided: false,
parent_index: None,
vertex_attribute_names: Vec::new(),
metadata: HashMap::new(),
skeleton_index: None,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct PointSet {
pub name: String,
pub positions: Vec<[f32; 3]>,
pub colors: Vec<[f32; 4]>,
pub scalars: Vec<f32>,
pub scalar_attributes: HashMap<String, Vec<f32>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ShDegree {
Zero,
One,
Three,
}
impl ShDegree {
pub fn coeff_count(self) -> usize {
match self {
Self::Zero => 3,
Self::One => 12,
Self::Three => 48,
}
}
}
#[derive(Clone, Debug)]
pub struct GaussianSplatSet {
pub positions: Vec<[f32; 3]>,
pub scales: Vec<[f32; 3]>,
pub rotations: Vec<[f32; 4]>,
pub opacities: Vec<f32>,
pub sh_coefficients: Vec<f32>,
pub sh_degree: ShDegree,
}
impl Default for GaussianSplatSet {
fn default() -> Self {
Self {
positions: Vec::new(),
scales: Vec::new(),
rotations: Vec::new(),
opacities: Vec::new(),
sh_coefficients: Vec::new(),
sh_degree: ShDegree::Zero,
}
}
}
impl PointSet {
pub fn to_gaussian_splats(
&self,
default_scale: [f32; 3],
default_opacity: f32,
) -> GaussianSplatSet {
let count = self.positions.len();
let mut sh_coefficients = Vec::with_capacity(count * 3);
for index in 0..count {
let rgb = self
.colors
.get(index)
.copied()
.map(|color| [color[0], color[1], color[2]])
.unwrap_or([1.0, 1.0, 1.0]);
sh_coefficients.extend_from_slice(&rgb);
}
GaussianSplatSet {
positions: self.positions.clone(),
scales: vec![default_scale; count],
rotations: vec![[0.0, 0.0, 0.0, 1.0]; count],
opacities: vec![default_opacity; count],
sh_coefficients,
sh_degree: ShDegree::Zero,
}
}
}
#[derive(Clone, Debug)]
pub enum VolumeGridGeometry {
Uniform {
origin: [f32; 3],
spacing: [f32; 3],
},
Rectilinear {
xs: Vec<f32>,
ys: Vec<f32>,
zs: Vec<f32>,
},
}
impl Default for VolumeGridGeometry {
fn default() -> Self {
Self::Uniform {
origin: [0.0, 0.0, 0.0],
spacing: [1.0, 1.0, 1.0],
}
}
}
#[derive(Clone, Debug, Default)]
pub struct StructuredVolume {
pub name: String,
pub dims: [u32; 3],
pub geometry: VolumeGridGeometry,
pub point_fields: HashMap<String, Vec<f32>>,
pub cell_fields: HashMap<String, Vec<f32>>,
}
impl StructuredVolume {
pub fn bounds(&self) -> ([f32; 3], [f32; 3]) {
match &self.geometry {
VolumeGridGeometry::Uniform { origin, spacing } => {
let max = [
origin[0] + spacing[0] * self.dims[0].saturating_sub(1) as f32,
origin[1] + spacing[1] * self.dims[1].saturating_sub(1) as f32,
origin[2] + spacing[2] * self.dims[2].saturating_sub(1) as f32,
];
(*origin, max)
}
VolumeGridGeometry::Rectilinear { xs, ys, zs } => {
let min = [
*xs.first().unwrap_or(&0.0),
*ys.first().unwrap_or(&0.0),
*zs.first().unwrap_or(&0.0),
];
let max = [
*xs.last().unwrap_or(&0.0),
*ys.last().unwrap_or(&0.0),
*zs.last().unwrap_or(&0.0),
];
(min, max)
}
}
}
pub fn scalar_values(&self, name: &str) -> Option<&[f32]> {
if let Some(values) = self.point_fields.get(name) {
return Some(values);
}
self.cell_fields.get(name).map(Vec::as_slice)
}
}
#[derive(Clone, Debug, Default)]
pub struct SparseGrid {
pub origin: [f32; 3],
pub cell_size: f32,
pub active_cells: Vec<[u32; 3]>,
pub cell_fields: HashMap<String, Vec<f32>>,
pub node_fields: HashMap<String, Vec<f32>>,
pub cell_colors: HashMap<String, Vec<[f32; 4]>>,
}
#[derive(Clone, Debug, Default)]
pub struct VolumeMesh {
pub positions: Vec<[f32; 3]>,
pub cells: Vec<[u32; 8]>,
pub cell_fields: HashMap<String, Vec<f32>>,
pub cell_colors: HashMap<String, Vec<[f32; 4]>>,
}
#[derive(Clone, Debug, Default)]
pub struct DecodedDataSet {
pub name: String,
pub surface_mesh: Option<SurfaceMesh>,
pub point_set: Option<PointSet>,
pub volume: Option<StructuredVolume>,
pub sparse_grid: Option<Box<SparseGrid>>,
pub volume_mesh: Option<Box<VolumeMesh>>,
}
impl DecodedDataSet {
pub fn as_surface_mesh(&self) -> Option<&SurfaceMesh> {
self.surface_mesh.as_ref()
}
pub fn as_point_set(&self) -> Option<&PointSet> {
self.point_set.as_ref()
}
pub fn as_structured_volume(&self) -> Option<&StructuredVolume> {
self.volume.as_ref()
}
pub fn as_sparse_grid(&self) -> Option<&SparseGrid> {
self.sparse_grid.as_deref()
}
pub fn as_volume_mesh(&self) -> Option<&VolumeMesh> {
self.volume_mesh.as_deref()
}
}
#[derive(Clone, Debug, Default)]
pub struct SceneData {
pub meshes: Vec<SceneMesh>,
pub materials: Vec<MaterialData>,
pub point_sets: Vec<PointSet>,
pub skeletons: Vec<Skeleton>,
pub animations: Vec<AnimationClip>,
}
pub(crate) type TextureData = RasterImageData;
pub(crate) type HdrTextureData = HdrImageData;
pub(crate) type IoMaterial = MaterialData;
pub(crate) type IoMesh = SceneMesh;
pub(crate) type IoPointCloud = PointSet;
pub(crate) type IoVolumeGeometry = VolumeGridGeometry;
pub(crate) type IoVolume = StructuredVolume;
pub(crate) type IoSparseVolume = SparseGrid;
pub(crate) type IoVolumeMesh = VolumeMesh;
pub(crate) type IoDataSet = DecodedDataSet;
pub(crate) type IoScene = SceneData;