diff options
Diffstat (limited to 'crates/render-core/src')
| -rw-r--r-- | crates/render-core/src/lib.rs | 51 | ||||
| -rw-r--r-- | crates/render-core/src/tests.rs | 102 |
2 files changed, 126 insertions, 27 deletions
diff --git a/crates/render-core/src/lib.rs b/crates/render-core/src/lib.rs index ddb93fb..d06761a 100644 --- a/crates/render-core/src/lib.rs +++ b/crates/render-core/src/lib.rs @@ -1,5 +1,7 @@ use msh_core::Model; +pub const DEFAULT_UV_SCALE: f32 = 1024.0; + #[derive(Clone, Debug)] pub struct RenderVertex { pub position: [f32; 3], @@ -58,7 +60,12 @@ pub fn build_render_mesh(model: &Model, lod: usize, group: usize) -> RenderMesh 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]) + .map(|packed| { + [ + packed[0] as f32 / DEFAULT_UV_SCALE, + packed[1] as f32 / DEFAULT_UV_SCALE, + ] + }) .unwrap_or([0.0, 0.0]); vertices.push(RenderVertex { position: *pos, @@ -76,38 +83,28 @@ pub fn build_render_mesh(model: &Model, lod: usize, group: usize) -> RenderMesh } pub fn compute_bounds(vertices: &[[f32; 3]]) -> Option<([f32; 3], [f32; 3])> { - let mut iter = vertices.iter(); - let first = iter.next()?; - let mut min_v = *first; - let mut max_v = *first; - - for v in iter { - for i in 0..3 { - if v[i] < min_v[i] { - min_v[i] = v[i]; - } - if v[i] > max_v[i] { - max_v[i] = v[i]; - } - } - } - - Some((min_v, max_v)) + compute_bounds_impl(vertices.iter().copied()) } 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; + compute_bounds_impl(vertices.iter().map(|v| v.position)) +} + +fn compute_bounds_impl<I>(mut positions: I) -> Option<([f32; 3], [f32; 3])> +where + I: Iterator<Item = [f32; 3]>, +{ + let first = positions.next()?; + let mut min_v = first; + let mut max_v = first; - for v in iter { + for pos in positions { for i in 0..3 { - if v.position[i] < min_v[i] { - min_v[i] = v.position[i]; + if pos[i] < min_v[i] { + min_v[i] = pos[i]; } - if v.position[i] > max_v[i] { - max_v[i] = v.position[i]; + if pos[i] > max_v[i] { + max_v[i] = pos[i]; } } } diff --git a/crates/render-core/src/tests.rs b/crates/render-core/src/tests.rs index 22103c6..c9b55a0 100644 --- a/crates/render-core/src/tests.rs +++ b/crates/render-core/src/tests.rs @@ -129,3 +129,105 @@ fn compute_bounds_for_mesh_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]); } + +fn nodes_with_slot_refs(slot_ids: &[Option<u16>]) -> Vec<u8> { + let mut out = vec![0u8; slot_ids.len().saturating_mul(38)]; + for (node_index, slot_id) in slot_ids.iter().copied().enumerate() { + let node_off = node_index * 38; + for i in 0..15 { + let off = node_off + 8 + i * 2; + out[off..off + 2].copy_from_slice(&u16::MAX.to_le_bytes()); + } + if let Some(slot_id) = slot_id { + out[node_off + 8..node_off + 10].copy_from_slice(&slot_id.to_le_bytes()); + } + } + out +} + +fn slot(batch_start: u16, batch_count: u16) -> msh_core::Slot { + msh_core::Slot { + tri_start: 0, + tri_count: 0, + batch_start, + batch_count, + aabb_min: [0.0; 3], + aabb_max: [0.0; 3], + sphere_center: [0.0; 3], + sphere_radius: 0.0, + opaque: [0; 5], + } +} + +fn batch(index_start: u32, index_count: u16, base_vertex: u32) -> msh_core::Batch { + msh_core::Batch { + batch_flags: 0, + material_index: 0, + opaque4: 0, + opaque6: 0, + index_count, + index_start, + opaque14: 0, + base_vertex, + } +} + +#[test] +fn build_render_mesh_handles_empty_slot_model() { + let model = msh_core::Model { + node_stride: 38, + node_count: 1, + nodes_raw: nodes_with_slot_refs(&[None]), + slots: Vec::new(), + positions: vec![[0.0, 0.0, 0.0]], + normals: None, + uv0: None, + indices: Vec::new(), + batches: Vec::new(), + node_names: None, + }; + + let mesh = build_render_mesh(&model, 0, 0); + assert!(mesh.vertices.is_empty()); + assert_eq!(mesh.batch_count, 0); + assert_eq!(mesh.triangle_count(), 0); +} + +#[test] +fn build_render_mesh_supports_multi_node_and_uv_scaling() { + let model = msh_core::Model { + node_stride: 38, + node_count: 2, + nodes_raw: nodes_with_slot_refs(&[Some(0), Some(1)]), + slots: vec![slot(0, 1), slot(1, 1)], + positions: vec![ + [0.0, 0.0, 0.0], + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [2.0, 0.0, 0.0], + [3.0, 0.0, 0.0], + [2.0, 1.0, 0.0], + ], + normals: None, + uv0: Some(vec![ + [1024, -1024], + [512, 256], + [0, 0], + [1024, 1024], + [2048, 1024], + [1024, 0], + ]), + indices: vec![0, 1, 2, 0, 1, 2], + batches: vec![batch(0, 3, 0), batch(3, 3, 3)], + node_names: None, + }; + + let mesh = build_render_mesh(&model, 0, 0); + assert_eq!(mesh.batch_count, 2); + assert_eq!(mesh.vertices.len(), 6); + assert_eq!(mesh.triangle_count(), 2); + assert_eq!(mesh.vertices[0].uv0, [1.0, -1.0]); + assert_eq!(mesh.vertices[1].uv0, [0.5, 0.25]); + assert_eq!(mesh.vertices[2].uv0, [0.0, 0.0]); + assert_eq!(mesh.vertices[3].uv0, [1.0, 1.0]); +} |
