diff --git a/crates/renderling-shader/src/bits.rs b/crates/renderling-shader/src/bits.rs index 18f8cc54..6f224353 100644 --- a/crates/renderling-shader/src/bits.rs +++ b/crates/renderling-shader/src/bits.rs @@ -2,6 +2,8 @@ use core::ops::RangeInclusive; +use crate::{id::Id, slab::Slab}; + /// Statically define a shift/mask range as a literal range of bits. pub const fn bits(range: RangeInclusive) -> (u32, u32) { let mut start = *range.start(); @@ -49,70 +51,127 @@ pub const U16_0_BITS: (u32, u32) = bits(0..=15); /// The shift/mask range for the second 16 bits of a u32. pub const U16_1_BITS: (u32, u32) = bits(16..=31); -/// Extract the "nth" 8 bits of the u32 at the given index in the slab. +/// Extract 8 bits of the u32 at the given index in the slab. /// /// Returns the extracted value, the index of the next component and the index /// of the next u32 in the slab. pub fn extract_u8( - // component index, eg 0 for the first 8 bits, 1 for the second 8 bits, etc - n: u32, // index of the u32 in the slab u32_index: usize, + // eg 0 for the first 8 bits, 1 for the second 8 bits, etc + byte_offset: usize, // slab of u32s slab: &[u32], -) -> (u32, u32, usize) { - match n { - 0 => (extract(slab[u32_index], U8_0_BITS), 1, u32_index), - 1 => (extract(slab[u32_index], U8_1_BITS), 2, u32_index), - 2 => (extract(slab[u32_index], U8_2_BITS), 3, u32_index), - _ => (extract(slab[u32_index], U8_3_BITS), 0, u32_index + 1), - } +) -> (u32, usize, usize) { + const SHIFT_MASKS: [((u32, u32), usize); 4] = [ + (U8_0_BITS, 0), + (U8_1_BITS, 0), + (U8_2_BITS, 0), + (U8_3_BITS, 1), + ]; + let byte_mod = byte_offset % 4; + let (shift_mask, index_inc) = SHIFT_MASKS[byte_mod as usize]; + let u32_value = slab.read(Id::from(u32_index)); + let value = extract(u32_value, shift_mask); + (value, u32_index + index_inc as usize, byte_mod + 1) } -/// Extract the "nth" 8 bits of the u32 at the given index in the slab. +/// Extract 8 bits of the u32 at the given index in the slab. /// /// Returns the extracted value, the index of the next component and the index /// of the next u32 in the slab. pub fn extract_i8( - // component index, eg 0 for the first 8 bits, 1 for the second 8 bits, etc - n: u32, // index of the u32 in the slab u32_index: usize, + // eg 0 for the first 8 bits, 1 for the second 8 bits, etc + byte_offset: usize, // slab of u32s slab: &[u32], -) -> (i32, u32, usize) { - let (value, n, u32_index) = extract_u8(n, u32_index, slab); +) -> (i32, usize, usize) { + let (value, u32_index, n) = extract_u8(u32_index, byte_offset, slab); let value: i32 = (value as i32 & 0xFF) - ((value as i32 & 0x80) << 1); - (value, n, u32_index) + (value, u32_index, n) } -/// Extract the "nth" 16 bits of the u32 at the given index in the slab. +/// Extract 16 bits of the u32 at the given index in the slab. pub fn extract_u16( - // component index, eg 0 for the first 16 bits, 1 for the second 16 bits, etc - n: u32, // index of the u32 in the slab u32_index: usize, + // eg 0 for the first 16 bits, 2 for the second 16 bits, etc + byte_offset: usize, // slab of u32s slab: &[u32], -) -> (u32, u32, usize) { - match n { - 0 => (extract(slab[u32_index], U16_0_BITS), 1, u32_index), - _ => (extract(slab[u32_index], U16_1_BITS), 0, u32_index + 1), - } +) -> (u32, usize, usize) { + // NOTE: This should only have two entries, but we'll still handle the case where + // the extraction is not aligned to a u32 boundary by reading as if it were, and then + // re-aligning. + const SHIFT_MASKS: [((u32, u32), usize, usize); 4] = [ + (U16_0_BITS, 2, 0), + (U16_0_BITS, 2, 0), + (U16_1_BITS, 0, 1), + (U16_1_BITS, 0, 1), + ]; + let byte_mod = byte_offset % 4; + crate::println!("byte_mod: {byte_mod}"); + let (shift_mask, next_byte_offset, index_inc) = SHIFT_MASKS[byte_mod as usize]; + let u32_value = slab.read(Id::from(u32_index)); + crate::println!("u32: {:032b}", u32_value); + let value = extract(u32_value, shift_mask); + crate::println!("u16: {:016b}", value); + crate::println!("u32: {:?}", u32_value); + (value, u32_index + index_inc, next_byte_offset) } -/// Extract the "nth" 16 bits of the u32 at the given index in the slab. +/// Extract 16 bits of the u32 at the given index in the slab. pub fn extract_i16( - // component index, eg 0 for the first 16 bits, 1 for the second 16 bits, etc - n: u32, // index of the u32 in the slab u32_index: usize, + // eg 0 for the first 16 bits, 1 for the second 16 bits, etc + byte_offset: usize, // slab of u32s slab: &[u32], -) -> (i32, u32, usize) { - let (value, n, u32_index) = extract_u16(n, u32_index, slab); +) -> (i32, usize, usize) { + let (value, u32_index, n) = extract_u16(u32_index, byte_offset, slab); let value: i32 = (value as i32 & 0xFFFF) - ((value as i32 & 0x8000) << 1); - (value, n, u32_index) + (value, u32_index, n) +} + +/// Extract 32 bits of the u32 at the given index in the slab. +pub fn extract_u32( + // index of the u32 in the slab + u32_index: usize, + // ignored and always passed back as `0` + _byte_offset: usize, + // slab of u32s + slab: &[u32], +) -> (u32, usize, usize) { + (slab.read(Id::from(u32_index)), u32_index + 1, 0) +} + +/// Extract 32 bits of the u32 at the given index in the slab. +pub fn extract_i32( + // index of the u32 in the slab + u32_index: usize, + // ignored and always passed back as `0` + _byte_offset: usize, + // slab of u32s + slab: &[u32], +) -> (i32, usize, usize) { + let (value, _, _) = extract_u32(u32_index, 0, slab); + (value as i32, u32_index + 1, 0) +} + +/// Extract 32 bits of the u32 at the given index in the slab. +pub fn extract_f32( + // index of the u32 in the slab + u32_index: usize, + // ignored and always passed back as `0` + _byte_offset: usize, + // slab of u32s + slab: &[u32], +) -> (f32, usize, usize) { + let (value, _, _) = extract_u32(u32_index, 0, slab); + (f32::from_bits(value), u32_index + 1, 0) } #[cfg(test)] @@ -169,12 +228,12 @@ mod test { let u32_slab: &[u32] = bytemuck::cast_slice(&u8_slab); let index = 0; let n = 0; - let (a, n, index) = extract_u8(n, index, u32_slab); - let (b, n, index) = extract_u8(n, index, u32_slab); - let (c, n, index) = extract_u8(n, index, u32_slab); - let (d, n, index) = extract_u8(n, index, u32_slab); - let (e, n, index) = extract_u8(n, index, u32_slab); - let (f, _, _) = extract_u8(n, index, u32_slab); + let (a, index, n) = extract_u8(index, n, u32_slab); + let (b, index, n) = extract_u8(index, n, u32_slab); + let (c, index, n) = extract_u8(index, n, u32_slab); + let (d, index, n) = extract_u8(index, n, u32_slab); + let (e, index, n) = extract_u8(index, n, u32_slab); + let (f, _, _) = extract_u8(index, n, u32_slab); assert_eq!([0, 1, 2, 3, 4, 5], [a, b, c, d, e, f]); } @@ -184,12 +243,12 @@ mod test { let u32_slab: &[u32] = bytemuck::cast_slice(&i8_slab); let index = 0; let n = 0; - let (a, n, index) = extract_i8(n, index, u32_slab); - let (b, n, index) = extract_i8(n, index, u32_slab); - let (c, n, index) = extract_i8(n, index, u32_slab); - let (d, n, index) = extract_i8(n, index, u32_slab); - let (e, n, index) = extract_i8(n, index, u32_slab); - let (f, _, _) = extract_i8(n, index, u32_slab); + let (a, index, n) = extract_i8(index, n, u32_slab); + let (b, index, n) = extract_i8(index, n, u32_slab); + let (c, index, n) = extract_i8(index, n, u32_slab); + let (d, index, n) = extract_i8(index, n, u32_slab); + let (e, index, n) = extract_i8(index, n, u32_slab); + let (f, _, _) = extract_i8(index, n, u32_slab); assert_eq!([0, -1, -2, -3, 4, 5], [a, b, c, d, e, f]); } @@ -199,12 +258,12 @@ mod test { let u32_slab: &[u32] = bytemuck::cast_slice(&u16_slab); let index = 0; let n = 0; - let (a, n, index) = extract_u16(n, index, u32_slab); - let (b, n, index) = extract_u16(n, index, u32_slab); - let (c, n, index) = extract_u16(n, index, u32_slab); - let (d, n, index) = extract_u16(n, index, u32_slab); - let (e, n, index) = extract_u16(n, index, u32_slab); - let (f, _, _) = extract_u16(n, index, u32_slab); + let (a, index, n) = extract_u16(index, n, u32_slab); + let (b, index, n) = extract_u16(index, n, u32_slab); + let (c, index, n) = extract_u16(index, n, u32_slab); + let (d, index, n) = extract_u16(index, n, u32_slab); + let (e, index, n) = extract_u16(index, n, u32_slab); + let (f, _, _) = extract_u16(index, n, u32_slab); assert_eq!([0, 1, 2, 3, 4, 5], [a, b, c, d, e, f]); } @@ -214,13 +273,84 @@ mod test { let u32_slab: &[u32] = bytemuck::cast_slice(&i16_slab); let index = 0; let n = 0; - let (a, n, index) = extract_i16(n, index, u32_slab); - let (b, n, index) = extract_i16(n, index, u32_slab); - let (c, n, index) = extract_i16(n, index, u32_slab); - let (d, n, index) = extract_i16(n, index, u32_slab); - let (e, n, index) = extract_i16(n, index, u32_slab); - let (f, n, index) = extract_i16(n, index, u32_slab); - let (g, _, _) = extract_i16(n, index, u32_slab); + let (a, index, n) = extract_i16(index, n, u32_slab); + let (b, index, n) = extract_i16(index, n, u32_slab); + let (c, index, n) = extract_i16(index, n, u32_slab); + let (d, index, n) = extract_i16(index, n, u32_slab); + let (e, index, n) = extract_i16(index, n, u32_slab); + let (f, index, n) = extract_i16(index, n, u32_slab); + let (g, _, _) = extract_i16(index, n, u32_slab); assert_eq!([0, -1, -2, -3, 4, 5, -12345], [a, b, c, d, e, f, g]); } + + #[test] + fn extract_u32_sanity() { + let u32_slab = [0u32, 1u32, 2u32, 3u32, 4u32, 5u32]; + let u32_slab: &[u32] = bytemuck::cast_slice(&u32_slab); + let index = 0; + let n = 0; + let (a, index, n) = extract_u32(index, n, u32_slab); + let (b, index, n) = extract_u32(index, n, u32_slab); + let (c, index, n) = extract_u32(index, n, u32_slab); + let (d, index, n) = extract_u32(index, n, u32_slab); + let (e, index, n) = extract_u32(index, n, u32_slab); + let (f, _, _) = extract_u32(index, n, u32_slab); + assert_eq!([0, 1, 2, 3, 4, 5], [a, b, c, d, e, f]); + } + + #[test] + fn extract_i32_sanity() { + let i32_slab = [0i32, -1i32, -2i32, -3i32, 4i32, 5i32, -12345i32]; + let u32_slab: &[u32] = bytemuck::cast_slice(&i32_slab); + let index = 0; + let n = 0; + let (a, index, n) = extract_i32(index, n, u32_slab); + let (b, index, n) = extract_i32(index, n, u32_slab); + let (c, index, n) = extract_i32(index, n, u32_slab); + let (d, index, n) = extract_i32(index, n, u32_slab); + let (e, index, n) = extract_i32(index, n, u32_slab); + let (f, index, n) = extract_i32(index, n, u32_slab); + let (g, _, _) = extract_i32(index, n, u32_slab); + assert_eq!([0, -1, -2, -3, 4, 5, -12345], [a, b, c, d, e, f, g]); + } + + #[test] + fn extract_f32_sanity() { + let f32_slab = [ + 0.0f32, + -1.0f32, + -2.0f32, + -3.0f32, + 4.0f32, + 5.0f32, + -12345.0f32, + ]; + let u32_slab: &[u32] = bytemuck::cast_slice(&f32_slab); + let index = 0; + let n = 0; + let (a, index, n) = extract_f32(index, n, u32_slab); + let (b, index, n) = extract_f32(index, n, u32_slab); + let (c, index, n) = extract_f32(index, n, u32_slab); + let (d, index, n) = extract_f32(index, n, u32_slab); + let (e, index, n) = extract_f32(index, n, u32_slab); + let (f, index, n) = extract_f32(index, n, u32_slab); + let (g, _, _) = extract_f32(index, n, u32_slab); + assert_eq!( + [0f32, -1f32, -2f32, -3f32, 4f32, 5f32, -12345f32], + [a, b, c, d, e, f, g] + ); + } + + #[test] + fn indices_sanity() { + let slab: [u32; 20] = [ + 65536, 2, 0, 0, 0, 1065353216, 0, 0, 0, 1065353216, 0, 0, 0, 1065353216, 0, 0, + 1065353216, 0, 0, 1065353216, + ]; + let u32_index = 9usize; + let byte_offset = 0usize; + let (a, u32_index, byte_offset) = extract_u32(u32_index, byte_offset, &slab); + let (b, u32_index, byte_offset) = extract_u32(u32_index, byte_offset, &slab); + let (c, u32_index, byte_offset) = extract_u32(u32_index, byte_offset, &slab); + } } diff --git a/crates/renderling-shader/src/gltf.rs b/crates/renderling-shader/src/gltf.rs index a4753d57..86802f6b 100644 --- a/crates/renderling-shader/src/gltf.rs +++ b/crates/renderling-shader/src/gltf.rs @@ -1,5 +1,5 @@ //! Gltf types that are used in shaders. -use glam::Vec4; +use glam::{Vec2, Vec3, Vec4}; use crate::{ self as renderling_shader, @@ -131,70 +131,258 @@ pub struct GltfAccessor { pub normalized: bool, } -macro_rules! println { - ($($arg:tt)*) => { - #[cfg(not(target_arch = "spirv"))] - { - std::println!($($arg)*); - } +/// Used to access contiguous u8 components from a buffer, contained in u32s. +pub struct IncU8 { + slab_index: usize, + byte_offset: usize, +} + +impl IncU8 { + pub fn extract(self, slab: &[u32]) -> (u32, Self) { + let (value, slab_index, byte_offset) = + crate::bits::extract_u8(self.slab_index, self.byte_offset, slab); + ( + value, + Self { + slab_index, + byte_offset, + }, + ) + } +} + +/// Used to access contiguous i8 components from a buffer, contained in u32s. +pub struct IncI8 { + slab_index: usize, + byte_offset: usize, +} + +impl IncI8 { + pub fn extract(self, slab: &[u32]) -> (i32, Self) { + let (value, slab_index, byte_offset) = + crate::bits::extract_i8(self.slab_index, self.byte_offset, slab); + ( + value, + Self { + slab_index, + byte_offset, + }, + ) + } +} + +/// Used to access contiguous u16 components from a buffer, contained in u32s. +pub struct IncU16 { + slab_index: usize, + byte_offset: usize, +} + +impl IncU16 { + pub fn extract(self, slab: &[u32]) -> (u32, Self) { + let (value, slab_index, byte_offset) = + crate::bits::extract_u16(self.slab_index, self.byte_offset, slab); + crate::println!("value: {value:?}"); + ( + value, + Self { + slab_index, + byte_offset, + }, + ) + } +} + +/// Used to access contiguous i16 components from a buffer, contained in u32s. +pub struct IncI16 { + slab_index: usize, + byte_offset: usize, +} + +impl IncI16 { + pub fn extract(self, slab: &[u32]) -> (i32, Self) { + let (value, slab_index, byte_offset) = + crate::bits::extract_i16(self.slab_index, self.byte_offset, slab); + ( + value, + Self { + slab_index, + byte_offset, + }, + ) } } impl GltfAccessor { - /// Retreive one component of the nth element. - pub fn get(&self, index: usize, component_index: usize, slab: &[u32]) -> u32 { - println!("get {index} {component_index}"); + fn slab_index_and_byte_offset(&self, element_index: usize, slab: &[u32]) -> (usize, usize) { + crate::println!("index: {element_index:?}"); + let buffer_id = self.buffer; + crate::println!("buffer_id: {buffer_id:?}"); let buffer = slab.read(self.buffer); - println!("buffer: {buffer:?}"); - let buffer_start = buffer.0.at(0); - let buffer_start_bytes = buffer_start.index() * 4; - let (mask, component_bytes, mut component_shift) = match self.data_type { - DataType::I8 => (0xF, 1, 8), - DataType::U8 => (0xF, 1, 8), - DataType::I16 => (0xFF, 2, 16), - DataType::U16 => (0xFF, 2, 16), - DataType::U32 => (0xFFFF, 4, 0), - DataType::F32 => (0xFFFF, 4, 0), - }; - component_shift *= component_index as u32; - let component_byte_offset = component_bytes * component_index; + crate::println!("buffer: {:?}", buffer); + let buffer_start = buffer.0.starting_index(); + crate::println!("buffer_start: {buffer_start:?}"); + let buffer_start_bytes = buffer_start * 4; + crate::println!("buffer_start_bytes: {buffer_start_bytes:?}"); let byte_offset = buffer_start_bytes + self.view_offset as usize - + index * self.size as usize - + component_byte_offset; - println!("byte_offset: {byte_offset}"); - let u32_offset = byte_offset / 4; - println!("u32_offset: {u32_offset}"); - let mut t = 0u32; - t.read_slab(u32_offset, slab); - let byte_mod = byte_offset as u32 % 4; - println!("byte_mod: {byte_mod}"); - let shift = match byte_mod { - 0 => 0, - 1 => 8, - 2 => 16, - 3 => 24, - _ => 0, // unreachable - }; - println!("mask: {mask:04x}"); - println!("shift: {shift}"); - println!("component_shift: {component_shift}"); - let u = crate::bits::extract(t, (shift + component_shift, mask)); - println!("u: {u}"); - u + + element_index as usize + * if self.size > self.view_stride { + self.size + } else { + self.view_stride + } as usize; + crate::println!("byte_offset: {byte_offset:?}"); + let slab_index = byte_offset / 4; + crate::println!("slab_index: {slab_index:?}"); + let byte_offset = byte_offset % 4; + (slab_index, byte_offset) + } + + pub fn inc_u8(&self, index: usize, slab: &[u32]) -> IncU8 { + let (slab_index, byte_offset) = self.slab_index_and_byte_offset(index, slab); + IncU8 { + slab_index, + byte_offset, + } + } + + pub fn inc_i8(&self, index: usize, slab: &[u32]) -> IncI8 { + let (slab_index, byte_offset) = self.slab_index_and_byte_offset(index, slab); + IncI8 { + slab_index, + byte_offset, + } + } + + pub fn inc_u16(&self, index: usize, slab: &[u32]) -> IncU16 { + let (slab_index, byte_offset) = self.slab_index_and_byte_offset(index, slab); + IncU16 { + slab_index, + byte_offset, + } + } + + pub fn inc_i16(&self, index: usize, slab: &[u32]) -> IncI16 { + let (slab_index, byte_offset) = self.slab_index_and_byte_offset(index, slab); + IncI16 { + slab_index, + byte_offset, + } } pub fn get_u32(&self, vertex_index: usize, slab: &[u32]) -> u32 { - self.get(vertex_index, 0, slab) + let x; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as u32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as u32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0 as u32; + } + } + x } pub fn get_f32(&self, vertex_index: usize, slab: &[u32]) -> f32 { - f32::from_bits(self.get(vertex_index, 0, slab)) + let x; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as f32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as f32; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as f32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, _) = inc.extract(slab); + x = ix as f32; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0 as f32; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0; + } + } + x } pub fn get_vec2(&self, vertex_index: usize, slab: &[u32]) -> glam::Vec2 { - let x = f32::from_bits(self.get(vertex_index, 0, slab)); - let y = f32::from_bits(self.get(vertex_index, 1, slab)); + let x; + let y; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0 as f32; + y = crate::bits::extract_u32(slab_index + 1, 0, slab).0 as f32; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0; + y = crate::bits::extract_f32(slab_index + 1, 0, slab).0; + } + } match self.dimensions { Dimensions::Scalar => glam::Vec2::new(x, 0.0), _ => glam::Vec2::new(x, y), @@ -202,9 +390,59 @@ impl GltfAccessor { } pub fn get_vec3(&self, vertex_index: usize, slab: &[u32]) -> glam::Vec3 { - let x = f32::from_bits(self.get(vertex_index, 0, slab)); - let y = f32::from_bits(self.get(vertex_index, 1, slab)); - let z = f32::from_bits(self.get(vertex_index, 2, slab)); + let x; + let y; + let z; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0 as f32; + y = crate::bits::extract_u32(slab_index + 1, 0, slab).0 as f32; + z = crate::bits::extract_u32(slab_index + 2, 0, slab).0 as f32; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0; + y = crate::bits::extract_f32(slab_index + 1, 0, slab).0; + z = crate::bits::extract_f32(slab_index + 2, 0, slab).0; + } + } match self.dimensions { Dimensions::Scalar => glam::Vec3::new(x, 0.0, 0.0), Dimensions::Vec2 => glam::Vec3::new(x, y, 0.0), @@ -213,10 +451,70 @@ impl GltfAccessor { } pub fn get_vec4(&self, vertex_index: usize, slab: &[u32]) -> glam::Vec4 { - let x = f32::from_bits(self.get(vertex_index, 0, slab)); - let y = f32::from_bits(self.get(vertex_index, 1, slab)); - let z = f32::from_bits(self.get(vertex_index, 2, slab)); - let w = f32::from_bits(self.get(vertex_index, 3, slab)); + let x; + let y; + let z; + let w; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + w = iw as f32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + w = iw as f32; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + w = iw as f32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as f32; + y = iy as f32; + z = iz as f32; + w = iw as f32; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0 as f32; + y = crate::bits::extract_u32(slab_index + 1, 0, slab).0 as f32; + z = crate::bits::extract_u32(slab_index + 2, 0, slab).0 as f32; + w = crate::bits::extract_u32(slab_index + 3, 0, slab).0 as f32; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0; + y = crate::bits::extract_f32(slab_index + 1, 0, slab).0; + z = crate::bits::extract_f32(slab_index + 2, 0, slab).0; + w = crate::bits::extract_f32(slab_index + 3, 0, slab).0; + } + } match self.dimensions { Dimensions::Scalar => glam::Vec4::new(x, 0.0, 0.0, 0.0), Dimensions::Vec2 => glam::Vec4::new(x, y, 0.0, 0.0), @@ -226,10 +524,70 @@ impl GltfAccessor { } pub fn get_uvec4(&self, vertex_index: usize, slab: &[u32]) -> glam::UVec4 { - let x = self.get_u32(vertex_index, slab); - let y = self.get_u32(vertex_index, slab); - let z = self.get_u32(vertex_index, slab); - let w = self.get_u32(vertex_index, slab); + let x; + let y; + let z; + let w; + match self.data_type { + DataType::I8 => { + let inc = self.inc_i8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as u32; + y = iy as u32; + z = iz as u32; + w = iw as u32; + } + DataType::U8 => { + let inc = self.inc_u8(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix; + y = iy; + z = iz; + w = iw; + } + DataType::I16 => { + let inc = self.inc_i16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix as u32; + y = iy as u32; + z = iz as u32; + w = iw as u32; + } + DataType::U16 => { + let inc = self.inc_u16(vertex_index, slab); + let (ix, inc) = inc.extract(slab); + let (iy, inc) = inc.extract(slab); + let (iz, inc) = inc.extract(slab); + let (iw, _) = inc.extract(slab); + x = ix; + y = iy; + z = iz; + w = iw; + } + DataType::U32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_u32(slab_index, 0, slab).0; + y = crate::bits::extract_u32(slab_index + 1, 0, slab).0; + z = crate::bits::extract_u32(slab_index + 2, 0, slab).0; + w = crate::bits::extract_u32(slab_index + 3, 0, slab).0; + } + DataType::F32 => { + let (slab_index, _) = self.slab_index_and_byte_offset(vertex_index, slab); + x = crate::bits::extract_f32(slab_index, 0, slab).0 as u32; + y = crate::bits::extract_f32(slab_index + 1, 0, slab).0 as u32; + z = crate::bits::extract_f32(slab_index + 2, 0, slab).0 as u32; + w = crate::bits::extract_f32(slab_index + 3, 0, slab).0 as u32; + } + } match self.dimensions { Dimensions::Scalar => glam::UVec4::new(x, 0, 0, 0), Dimensions::Vec2 => glam::UVec4::new(x, y, 0, 0), @@ -264,25 +622,87 @@ impl GltfPrimitive { } else { vertex_index }; - let positions = slab.read(self.positions); - let position = positions.get_vec3(index, slab); - let normals = slab.read(self.normals); - let normal = normals.get_vec3(index, slab); - let tangents = slab.read(self.tangents); - let tangent = tangents.get_vec4(index, slab); - let colors = slab.read(self.colors); - let color = colors.get_vec4(index, slab); - let tex_coords0 = slab.read(self.tex_coords0); - let tex_coords0 = tex_coords0.get_vec2(index, slab); - let tex_coords1 = slab.read(self.tex_coords1); - let tex_coords1 = tex_coords1.get_vec2(index, slab); + crate::println!("index: {index:?}"); + + let position = if self.positions.is_none() { + Vec3::ZERO + } else { + let positions = slab.read(self.positions); + crate::println!("positions: {positions:?}"); + positions.get_vec3(index, slab) + }; + crate::println!("position: {position:?}"); + + let normal = if self.normals.is_none() { + Vec3::Z + } else { + let normals = slab.read(self.normals); + crate::println!("normals: {normals:?}"); + normals.get_vec3(index, slab) + }; + crate::println!("normal: {normal:?}"); + + let tangent = if self.tangents.is_none() { + Vec4::Y + } else { + let tangents = slab.read(self.tangents); + crate::println!("tangents: {tangents:?}"); + tangents.get_vec4(index, slab) + }; + crate::println!("tangent: {tangent:?}"); + + let color = if self.colors.is_none() { + Vec4::ONE + } else { + let colors = slab.read(self.colors); + crate::println!("colors: {colors:?}"); + colors.get_vec4(index, slab) + }; + crate::println!("color: {color:?}"); + + let tex_coords0 = if self.tex_coords0.is_none() { + Vec2::ZERO + } else { + let tex_coords0 = slab.read(self.tex_coords0); + crate::println!("tex_coords0: {tex_coords0:?}"); + tex_coords0.get_vec2(index, slab) + }; + crate::println!("tex_coords0: {tex_coords0:?}"); + + let tex_coords1 = if self.tex_coords1.is_none() { + Vec2::ZERO + } else { + let tex_coords1 = slab.read(self.tex_coords1); + crate::println!("tex_coords1: {tex_coords1:?}"); + tex_coords1.get_vec2(index, slab) + }; + crate::println!("tex_coords1: {tex_coords1:?}"); + let uv = Vec4::new(tex_coords0.x, tex_coords0.y, tex_coords1.x, tex_coords1.y); - let joints = slab.read(self.joints); - let joints = joints.get_uvec4(index, slab); - let joints = [joints.x, joints.y, joints.z, joints.w]; - let weights = slab.read(self.weights); - let weights = weights.get_vec4(index, slab); - let weights = [weights.x, weights.y, weights.z, weights.w]; + crate::println!("uv: {uv:?}"); + + let joints = if self.joints.is_none() { + [0; 4] + } else { + let joints = slab.read(self.joints); + crate::println!("joints: {joints:?}"); + let joints = joints.get_uvec4(index, slab); + crate::println!("joints: {joints:?}"); + [joints.x, joints.y, joints.z, joints.w] + }; + crate::println!("joints: {joints:?}"); + + let weights = if self.weights.is_none() { + [0.0; 4] + } else { + let weights = slab.read(self.weights); + crate::println!("weights: {weights:?}"); + let weights = weights.get_vec4(index, slab); + crate::println!("weights: {weights:?}"); + [weights.x, weights.y, weights.z, weights.w] + }; + crate::println!("weights: {weights:?}"); + crate::stage::Vertex { position: position.extend(0.0), color, @@ -637,3 +1057,35 @@ pub struct GltfDocument { pub textures: Array, pub views: Array, } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn indices_accessor_sanity() { + // Taken from the indices accessor in the "simple meshes" gltf sample, + // but with the buffer changed to match where we write it here. + let buffer_id = Id::new(20); + let accessor = GltfAccessor { + size: 2, + buffer: buffer_id, + view_offset: 0, + view_stride: 0, + count: 3, + data_type: DataType::U16, + dimensions: Dimensions::Scalar, + normalized: false, + }; + let buffer = GltfBuffer(Array::new(0, 11)); + let mut slab: [u32; 22] = [ + 65536, 2, 0, 0, 0, 1065353216, 0, 0, 0, 1065353216, 0, 0, 0, 1065353216, 0, 0, + 1065353216, 0, 0, 1065353216, 0, 0, + ]; + slab.write(&buffer, buffer_id.index()); + let i0 = accessor.get_u32(0, &slab); + let i1 = accessor.get_u32(1, &slab); + let i2 = accessor.get_u32(2, &slab); + assert_eq!([0, 1, 2], [i0, i1, i2]); + } +} diff --git a/crates/renderling-shader/src/lib.rs b/crates/renderling-shader/src/lib.rs index b83aa085..d15b73fa 100644 --- a/crates/renderling-shader/src/lib.rs +++ b/crates/renderling-shader/src/lib.rs @@ -25,6 +25,18 @@ pub mod tonemapping; pub mod tutorial; pub mod ui; +#[allow(unused_macros)] +macro_rules! println { + ($($arg:tt)*) => { + #[cfg(not(target_arch = "spirv"))] + { + std::println!($($arg)*); + } + } +} + +pub(crate) use println; + /// Additional methods for vector types. pub trait IsVector { /// Normalize or return zero. diff --git a/crates/renderling-shader/src/stage.rs b/crates/renderling-shader/src/stage.rs index 71b20e51..83817f4b 100644 --- a/crates/renderling-shader/src/stage.rs +++ b/crates/renderling-shader/src/stage.rs @@ -1394,11 +1394,11 @@ pub fn test_i8_i16_extraction( #[spirv(global_invocation_id)] global_id: UVec3, ) { let index = global_id.x as usize; - let (value, _, _) = crate::bits::extract_i8(2, index, slab); + let (value, _, _) = crate::bits::extract_i8(index, 2, slab); if value > 0 { slab[index] = value as u32; } - let (value, _, _) = crate::bits::extract_i16(2, index, slab); + let (value, _, _) = crate::bits::extract_i16(index, 2, slab); if value > 0 { slab[index] = value as u32; } diff --git a/crates/renderling/src/linkage/stage-new_stage_vertex.spv b/crates/renderling/src/linkage/stage-new_stage_vertex.spv index 9e9fac85..7b194d66 100644 Binary files a/crates/renderling/src/linkage/stage-new_stage_vertex.spv and b/crates/renderling/src/linkage/stage-new_stage_vertex.spv differ diff --git a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv index d3a8e8ba..d685467f 100644 Binary files a/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv and b/crates/renderling/src/linkage/stage-test_i8_i16_extraction.spv differ diff --git a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv index 101332a8..e904b51a 100644 Binary files a/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv and b/crates/renderling/src/linkage/tutorial-slabbed_render_unit.spv differ diff --git a/crates/renderling/src/scene/gltf_support.rs b/crates/renderling/src/scene/gltf_support.rs index df4f3e29..63939261 100644 --- a/crates/renderling/src/scene/gltf_support.rs +++ b/crates/renderling/src/scene/gltf_support.rs @@ -1258,56 +1258,6 @@ mod test { img_diff::assert_img_eq("gltf_images.png", img); } - #[test] - // Ensures we can read a minimal gltf file with a simple triangle mesh. - fn minimal_mesh() { - let mut r = - Renderling::headless(20, 20).with_background_color(Vec3::splat(0.0).extend(1.0)); - let mut builder = r.new_scene(); - let _loader = builder - .gltf_load("../../gltf/gltfTutorial_003_MinimalGltfFile.gltf") - .unwrap(); - let projection = camera::perspective(20.0, 20.0); - let view = camera::look_at(Vec3::new(0.5, 0.5, 2.0), Vec3::new(0.5, 0.5, 0.0), Vec3::Y); - builder.set_camera(projection, view); - let scene = builder.build().unwrap(); - r.setup_render_graph(RenderGraphConfig { - scene: Some(scene), - with_screen_capture: true, - ..Default::default() - }); - - let img = r.render_image().unwrap(); - img_diff::assert_img_eq("gltf_minimal_mesh.png", img); - } - - #[test] - // ensures we can - // * read simple meshes - // * support multiple nodes that reference the same mesh - // * support primitives w/ positions and normal attributes - // * support transforming nodes (T * R * S) - fn simple_meshes() { - let mut r = - Renderling::headless(100, 50).with_background_color(Vec3::splat(0.0).extend(1.0)); - let mut builder = r.new_scene(); - let _loader = builder - .gltf_load("../../gltf/gltfTutorial_008_SimpleMeshes.gltf") - .unwrap(); - let projection = camera::perspective(100.0, 50.0); - let view = camera::look_at(Vec3::new(1.0, 0.5, 1.5), Vec3::new(1.0, 0.5, 0.0), Vec3::Y); - builder.set_camera(projection, view); - let scene = builder.build().unwrap(); - r.setup_render_graph(RenderGraphConfig { - scene: Some(scene), - with_screen_capture: true, - ..Default::default() - }); - - let img = r.render_image().unwrap(); - img_diff::assert_img_eq("gltf_simple_meshes.png", img); - } - #[test] fn simple_texture() { let size = 100; diff --git a/crates/renderling/src/stage/gltf_support.rs b/crates/renderling/src/stage/gltf_support.rs index 42ab75a8..a908e0b9 100644 --- a/crates/renderling/src/stage/gltf_support.rs +++ b/crates/renderling/src/stage/gltf_support.rs @@ -10,7 +10,7 @@ use crate::{ SceneImage, }; use glam::{Quat, Vec2, Vec3, Vec4}; -use renderling_shader::stage::Vertex; +use renderling_shader::stage::{Transform, Vertex}; use snafu::{OptionExt, ResultExt, Snafu}; #[derive(Debug, Snafu)] @@ -515,12 +515,11 @@ impl Stage { let normals_array = self.append_array(&normals); let buffer = GltfBuffer(normals_array.into_u32_array()); let buffer_id = self.append(&buffer); - debug_assert_eq!(8 * 3, std::mem::size_of::<[f32; 3]>()); let accessor = GltfAccessor { - size: 8 * 3, + size: 12, buffer: buffer_id, view_offset: 0, - view_stride: 8 * 3, + view_stride: 12, count: normals.len() as u32, data_type: DataType::F32, dimensions: Dimensions::Vec3, @@ -558,12 +557,11 @@ impl Stage { let tangents_array = self.append_array(&tangents); let buffer = GltfBuffer(tangents_array.into_u32_array()); let buffer_id = self.append(&buffer); - debug_assert_eq!(4 * 3, std::mem::size_of::<[f32; 3]>()); let accessor = GltfAccessor { - size: 8 * 3, + size: 12, buffer: buffer_id, view_offset: 0, - view_stride: 8 * 3, + view_stride: 12, count: tangents.len() as u32, data_type: DataType::F32, dimensions: Dimensions::Vec3, @@ -867,10 +865,16 @@ impl Stage { mesh, primitive_index: primitive.index() as u32, }); + let (t, r, s) = node.transform().decomposed(); + let transform = self.append(&Transform { + translation: Vec3::from(t), + rotation: Quat::from_array(r), + scale: Vec3::from(s), + }); let render_unit = RenderUnit { vertex_data: VertexData::Gltf(vertex_data_id), vertex_count: super::get_vertex_count(&primitive), - transform: Id::NONE, + transform, camera: camera_id, }; self.draw_unit(&render_unit) @@ -978,11 +982,11 @@ mod test { dimensions: Dimensions::Scalar, normalized: false, }; - let i0 = accessor.get(0, 0, &data); + let i0 = accessor.get_u32(0, &data); assert_eq!(1, i0); - let i1 = accessor.get(1, 0, &data); + let i1 = accessor.get_u32(1, &data); assert_eq!(1, i1); - let i2 = accessor.get(2, 0, &data); + let i2 = accessor.get_u32(2, &data); assert_eq!(1, i2); } @@ -1001,10 +1005,10 @@ mod test { let projection = crate::camera::perspective(100.0, 50.0); let position = Vec3::new(1.0, 0.5, 1.5); let view = crate::camera::look_at(position, Vec3::new(1.0, 0.5, 0.0), Vec3::Y); - let stage = Stage::new(device.clone(), queue.clone()); + let stage = Stage::new(device.clone(), queue.clone()).with_lighting(false); stage.configure_graph(&mut r, true); let gpu_doc = stage - .load_gltf_document(&document, buffers, images) + .load_gltf_document(&document, buffers.clone(), images) .unwrap(); let camera = Camera { projection, @@ -1025,6 +1029,7 @@ mod test { )) .unwrap(); + #[allow(unused)] #[derive(Debug, Default)] struct VertexInvocation { draw: DrawUnit, @@ -1047,6 +1052,15 @@ mod test { let draws = stage.get_draws(); let slab = &data; + for i in 0..gpu_doc.accessors.len() { + let accessor = slab.read(gpu_doc.accessors.at(i)); + println!("accessor {i}: {accessor:#?}", i = i, accessor = accessor); + let buffer = slab.read(accessor.buffer); + println!("buffer: {buffer:#?}"); + let buffer_data = slab.read_vec(buffer.0); + println!("buffer_data: {buffer_data:#?}"); + } + let indices = draws .iter() .map(|draw| { @@ -1075,80 +1089,87 @@ mod test { .collect::>(); assert_eq!([0, 1, 2], indices[0].as_slice()); assert_eq!([0, 1, 2], indices[1].as_slice()); - let clip_positions = draws - .iter() - .map(|draw| { - let unit_id = draw.id; - let unit = slab.read(unit_id); - let vertex_data_id = match unit.vertex_data { - renderling_shader::stage::VertexData::Native(_) => panic!("should be gltf"), - renderling_shader::stage::VertexData::Gltf(id) => id, - }; - let vertex_data = slab.read(vertex_data_id); - let mesh = slab.read(vertex_data.mesh); - let primitive_id = mesh.primitives.at(vertex_data.primitive_index as usize); - let primitive = slab.read(primitive_id); - let indices = if primitive.indices.is_some() { - let indices_accessor = slab.read(primitive.indices); - (0..draw.vertex_count) - .map(|i| { - let index = indices_accessor.get_u32(i as usize, slab); - index - }) - .collect::>() - } else { - (0..draw.vertex_count).collect::>() - }; - println!("positions\n\n"); - let pos_accessor = slab.read(primitive.positions); - indices - .into_iter() - .map(|index| pos_accessor.get_vec3(index as usize, slab)) - .collect::>() + + let invocations = draws + .into_iter() + .flat_map(|draw| { + let render_unit_id = draw.id; + let instance_index = render_unit_id.inner(); + let render_unit = data.read(render_unit_id); + let data = &data; + (0..draw.vertex_count).map(move |vertex_index| { + let mut invocation = VertexInvocation { + draw, + render_unit_id, + render_unit, + instance_index, + vertex_index, + ..Default::default() + }; + renderling_shader::stage::new_stage_vertex( + instance_index, + vertex_index, + data, + &mut invocation.out_camera, + &mut invocation.out_material, + &mut invocation.out_color, + &mut invocation.out_uv0, + &mut invocation.out_uv1, + &mut invocation.out_norm, + &mut invocation.out_tangent, + &mut invocation.out_bitangent, + &mut invocation.out_pos, + &mut invocation.clip_pos, + ); + invocation + }) }) .collect::>(); - panic!("clip_positions: {clip_positions:#?}"); + let seen_positions = invocations + .iter() + .map(|inv| inv.out_pos) + .take(3) + .collect::>(); + let mesh = document.meshes().next().unwrap(); + let prim = mesh.primitives().next().unwrap(); + let expected_positions_reader = prim.reader(|buffer| Some(&buffers[buffer.index()])); + let expected_positions = expected_positions_reader + .read_positions() + .unwrap() + .map(|pos| Vec3::from(pos)) + .collect::>(); + assert_eq!(expected_positions, seen_positions); + + let img = r.render_image().unwrap(); + img_diff::assert_img_eq("gltf_simple_meshes.png", img); + } - //let invocations = draws - // .into_iter() - // .map(|draw| { - // let render_unit_id = draw.id; - // let instance_index = render_unit_id.inner(); - // let render_unit = data.read(render_unit_id); - // let data = &data; - // (0..draw.vertex_count) - // .map(move |vertex_index| { - // let mut invocation = VertexInvocation { - // draw, - // render_unit_id, - // render_unit, - // instance_index, - // vertex_index, - // ..Default::default() - // }; - // renderling_shader::stage::new_stage_vertex( - // instance_index, - // vertex_index, - // data, - // &mut invocation.out_camera, - // &mut invocation.out_material, - // &mut invocation.out_color, - // &mut invocation.out_uv0, - // &mut invocation.out_uv1, - // &mut invocation.out_norm, - // &mut invocation.out_tangent, - // &mut invocation.out_bitangent, - // &mut invocation.out_pos, - // &mut invocation.clip_pos, - // ); - // invocation - // }) - // .collect::>() - // }) - // .collect::>(); - //panic!("vertex_invocations: {invocations:#?}"); + #[test] + // Ensures we can read a minimal gltf file with a simple triangle mesh. + fn minimal_mesh() { + let mut r = + Renderling::headless(20, 20).with_background_color(Vec3::splat(0.0).extend(1.0)); + let (device, queue) = r.get_device_and_queue_owned(); + let stage = Stage::new(device, queue).with_lighting(false); + stage.configure_graph(&mut r, true); + let (document, buffers, images) = + gltf::import("../../gltf/gltfTutorial_003_MinimalGltfFile.gltf").unwrap(); + let gpu_doc = stage + .load_gltf_document(&document, buffers, images) + .unwrap(); + let projection = crate::camera::perspective(20.0, 20.0); + let eye = Vec3::new(0.5, 0.5, 2.0); + let view = crate::camera::look_at(eye, Vec3::new(0.5, 0.5, 0.0), Vec3::Y); + let camera = Camera { + projection, + view, + position: Vec3::new(0.5, 0.5, 2.0), + }; + let camera_id = stage.append(&camera); + let default_scene = document.default_scene().unwrap(); + let _unit_ids = stage.draw_gltf_scene(&gpu_doc, camera_id, default_scene); let img = r.render_image().unwrap(); - img_diff::save("gltf_simple_meshes.png", img); + img_diff::assert_img_eq("gltf_minimal_mesh.png", img); } }