feat: begin implementation of material loader

This commit is contained in:
alphafetus committed 2026-09-03 12:21:47 -04:00
1 parent 20c1d2c0c8
commit 363c21136d
8 files changed
+122 -11

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
use std::path::Path;
use crate::loaders::material::mat_loader::{MaterialFileLoader, MaterialInfo};
pub struct GltfMaterialLoader;
impl MaterialFileLoader for GltfMaterialLoader {
fn load_material(&self, path: &Path) -> anyhow::Result<MaterialInfo> {
let (document, buffers, images) = gltf::import(path)?;
// We just want to read through the information to see what kinds of materials are available.
// I'm not sure how gltf defines materials, especially if they're applied to specific sets
// of vertices.
todo!()
}
}
+83
View File
@@ -0,0 +1,83 @@
use std::collections::HashMap;
use std::path::Path;
use thiserror::Error;
use anyhow::Result;
use crate::loaders::material::gltf_mat_loader::GltfMaterialLoader;
#[derive(Error, Debug)]
pub enum MaterialLoaderError {
#[error("file extension is missing")]
MissingExtension,
#[error("extension {0} is not supported")]
ExtensionNotSupported(String)
}
/// A material loader struct that handles multiple different file types.
/// List of supported and planned file formats:
/// - `.gltf`
/// - `.mtl` (planned, not implemented)
pub struct MaterialLoader {
loaders: HashMap<String, Box<dyn MaterialFileLoader>>,
}
impl MaterialLoader {
/// Creates a new `MaterialLoader` struct.
pub fn new() -> Self {
let mut loaders = HashMap::new();
loaders.insert("gltf".into(), Box::new(GltfMaterialLoader) as Box<dyn MaterialFileLoader>);
Self { loaders }
}
/// Loads a material from the given path. Note that some materials are loaded through their
/// mesh's file (GLTF embeds materials, however OBJ files have a separate .mtl file). These
/// quirks must be handled differently. Refer to the [`MaterialLoader`] for more information
/// on supported material files and which files to target.
pub fn load_material<P: AsRef<Path>>(&mut self, path: P) -> Result<MaterialInfo> {
let path = path.as_ref();
let file_ext = path.extension().and_then(|ext| ext.to_str())
.ok_or(MaterialLoaderError::MissingExtension)?;
self.loaders.get(file_ext)
.ok_or(MaterialLoaderError::ExtensionNotSupported(file_ext.to_string()))?
.load_material(path)
}
}
/// Contains all information required for the application to load a new material.
pub struct MaterialInfo {
/// The ID of this material
pub name: String,
/// The material uniforms. These should be defined on every imported material.
pub uniforms: MaterialUniforms,
/// The ID of the base color map, if any.
pub base_color_map: Option<String>,
/// The ID of the roughness map, if any. This is ignored for now.
pub roughness_map: Option<String>,
/// The ID of the normal map, if any. This is ignored for now.
pub normal_map: Option<String>,
}
/// A struct composed of the material uniforms. These uniforms will typically scale the material
/// texture maps if there are any. Refer to [`MaterialInfo`] for more information.
pub struct MaterialUniforms {
/// The base color of the material. This scales the base color texture, if any.
/// This value must be specified in normalized RGBA format (all values between 0 and 1).
pub base_color: [f32; 4],
/// The metalness of the material. This scales the metalness texture, if any. This value should
/// be specified as a normalized float between 0 and 1, based on an 8-bit number space.
///
/// This is ignored until the shaders are updated.
pub metalness_factor: f32,
/// The roughness of the material. This scales the roughness texture, if any. This value should
/// be specified as a normalized float between 0 and 1, based on an 8-bit number space.
///
/// This is ignored until the shaders are updated.
pub roughness_factor: f32,
}
/// A trait that must be implemented on all material loaders. Ensures consistent material
/// import/load information.
pub trait MaterialFileLoader {
fn load_material(&self, path: &Path) -> anyhow::Result<MaterialInfo>;
}
+2
View File
@@ -0,0 +1,2 @@
pub mod mat_loader;
pub mod gltf_mat_loader;
File renamed without changes.
@@ -1,5 +1,5 @@
use super::gltf_loader::*;
use crate::loaders::obj_loader::ObjLoader;
use crate::loaders::mesh::obj_loader::ObjLoader;
use anyhow::Result;
use std::collections::HashMap;
use std::path::Path;
@@ -20,10 +20,6 @@ pub trait MeshFileLoader {
fn load_mesh(&self, path: &Path) -> Result<MeshInfo>;
}
pub struct MeshLoader {
loaders: HashMap<String, Box<dyn MeshFileLoader>>,
}
#[derive(Error, Debug)]
pub enum MeshLoaderError {
#[error("file extension is missing")]
@@ -32,6 +28,14 @@ pub enum MeshLoaderError {
ExtensionNotSupported(String),
}
/// A mesh loader struct that handles multiple different file types. The list of supported and
/// planned file formats follows:
/// - `.gltf`
/// - `.obj`
pub struct MeshLoader {
loaders: HashMap<String, Box<dyn MeshFileLoader>>,
}
impl MeshLoader {
pub fn new() -> Self {
let mut loaders = HashMap::new();
@@ -48,7 +52,9 @@ impl MeshLoader {
Self { loaders }
}
/// Loads a mesh and returns a `Result` containing the information.
/// Loads a mesh from the given path. Note that materials are not automatically loaded through
/// this function, and must be manually loaded. Refer to the [`MeshLoader`] for more information
/// on what file types are supported.
pub fn load_mesh<P: AsRef<Path>>(&self, path: &P) -> Result<MeshInfo> {
let ext = path
.as_ref()
@@ -70,11 +76,11 @@ pub mod test_load_meshes {
use super::*;
fn load_gltf(loader: &MeshLoader) -> Result<MeshInfo> {
loader.load_mesh(&Path::new("meshes/laat_gltf/scene.gltf"))
loader.load_mesh(&Path::new("../../../meshes/laat_gltf/scene.gltf"))
}
fn load_obj(loader: &MeshLoader) -> Result<MeshInfo> {
loader.load_mesh(&Path::new("meshes/laat_gunship/scene.obj"))
loader.load_mesh(&Path::new("../../../meshes/laat_gunship/scene.obj"))
}
#[test]
+3
View File
@@ -0,0 +1,3 @@
pub mod gltf_loader;
pub mod mesh_loader;
mod obj_loader;
File renamed without changes.
+4 -3
View File
@@ -1,3 +1,4 @@
pub mod gltf_loader;
pub mod mesh_loader;
mod obj_loader;
pub mod mesh;
pub mod material;
pub use mesh::*;