feat: Enhance model and texture loading with improved error handling and new features
- Introduced `LoadedModel` and `LoadedTexture` structs for better encapsulation of model and texture data. - Added functions to load models and textures from archives, including support for resolving textures based on materials and wear entries. - Implemented error handling for missing textures, materials, and wear entries. - Updated the rendering pipeline to support texture loading and binding, including command-line arguments for texture customization. - Enhanced the `texm` crate with new decoding capabilities for various pixel formats, including indexed textures. - Added tests for texture decoding and loading to ensure reliability and correctness. - Updated documentation to reflect changes in the material and texture resolution process.
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
use msh_core::Model;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RenderVertex {
|
||||
pub position: [f32; 3],
|
||||
pub uv0: [f32; 2],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RenderMesh {
|
||||
pub vertices: Vec<[f32; 3]>,
|
||||
pub vertices: Vec<RenderVertex>,
|
||||
pub batch_count: usize,
|
||||
}
|
||||
|
||||
@@ -18,6 +24,7 @@ impl RenderMesh {
|
||||
pub fn build_render_mesh(model: &Model, lod: usize, group: usize) -> RenderMesh {
|
||||
let mut vertices = Vec::new();
|
||||
let mut batch_count = 0usize;
|
||||
let uv0 = model.uv0.as_ref();
|
||||
|
||||
for node_index in 0..model.node_count {
|
||||
let Some(slot_idx) = model.slot_index(node_index, lod, group) else {
|
||||
@@ -48,7 +55,15 @@ pub fn build_render_mesh(model: &Model, lod: usize, group: usize) -> RenderMesh
|
||||
let Some(pos) = model.positions.get(final_idx) else {
|
||||
continue;
|
||||
};
|
||||
vertices.push(*pos);
|
||||
let uv = uv0
|
||||
.and_then(|uvs| uvs.get(final_idx))
|
||||
.copied()
|
||||
.map(|packed| [packed[0] as f32 / 1024.0, packed[1] as f32 / 1024.0])
|
||||
.unwrap_or([0.0, 0.0]);
|
||||
vertices.push(RenderVertex {
|
||||
position: *pos,
|
||||
uv0: uv,
|
||||
});
|
||||
}
|
||||
batch_count += 1;
|
||||
}
|
||||
@@ -80,5 +95,25 @@ pub fn compute_bounds(vertices: &[[f32; 3]]) -> Option<([f32; 3], [f32; 3])> {
|
||||
Some((min_v, max_v))
|
||||
}
|
||||
|
||||
pub fn compute_bounds_for_mesh(vertices: &[RenderVertex]) -> Option<([f32; 3], [f32; 3])> {
|
||||
let mut iter = vertices.iter();
|
||||
let first = iter.next()?;
|
||||
let mut min_v = first.position;
|
||||
let mut max_v = first.position;
|
||||
|
||||
for v in iter {
|
||||
for i in 0..3 {
|
||||
if v.position[i] < min_v[i] {
|
||||
min_v[i] = v.position[i];
|
||||
}
|
||||
if v.position[i] > max_v[i] {
|
||||
max_v[i] = v.position[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some((min_v, max_v))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -74,9 +74,17 @@ fn build_render_mesh_for_real_models() {
|
||||
if !mesh.vertices.is_empty() {
|
||||
meshes_non_empty += 1;
|
||||
}
|
||||
if compute_bounds(&mesh.vertices).is_some() {
|
||||
if compute_bounds_for_mesh(&mesh.vertices).is_some() {
|
||||
bounds_non_empty += 1;
|
||||
}
|
||||
for vertex in &mesh.vertices {
|
||||
assert!(
|
||||
vertex.uv0[0].is_finite() && vertex.uv0[1].is_finite(),
|
||||
"UV must be finite for '{}' in {}",
|
||||
entry.meta.name,
|
||||
archive_path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,3 +107,25 @@ fn compute_bounds_handles_empty_and_non_empty() {
|
||||
assert_eq!(bounds.0, [-2.0, -1.0, 0.5]);
|
||||
assert_eq!(bounds.1, [1.0, 5.0, 9.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_bounds_for_mesh_handles_empty_and_non_empty() {
|
||||
assert!(compute_bounds_for_mesh(&[]).is_none());
|
||||
let bounds = compute_bounds_for_mesh(&[
|
||||
RenderVertex {
|
||||
position: [1.0, 2.0, 3.0],
|
||||
uv0: [0.0, 0.0],
|
||||
},
|
||||
RenderVertex {
|
||||
position: [-2.0, 5.0, 0.5],
|
||||
uv0: [0.2, 0.3],
|
||||
},
|
||||
RenderVertex {
|
||||
position: [0.0, -1.0, 9.0],
|
||||
uv0: [1.0, 1.0],
|
||||
},
|
||||
])
|
||||
.expect("bounds expected");
|
||||
assert_eq!(bounds.0, [-2.0, -1.0, 0.5]);
|
||||
assert_eq!(bounds.1, [1.0, 5.0, 9.0]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user