From 87aa9226b672dd02355890d068ab8499f507363d Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 29 Feb 2024 00:07:39 +0000 Subject: [PATCH 1/4] Support for normalizing vertex attributes --- format/src/flver/accessor.rs | 69 --------------- format/src/flver/mod.rs | 14 ++-- format/src/flver/vertex_buffer/accessor.rs | 84 +++++++++++++++++++ .../mod.rs} | 3 + .../src/flver/vertex_buffer/normalization.rs | 45 ++++++++++ viewer/src/flver/asset.rs | 2 +- 6 files changed, 139 insertions(+), 78 deletions(-) delete mode 100644 format/src/flver/accessor.rs create mode 100644 format/src/flver/vertex_buffer/accessor.rs rename format/src/flver/{vertex_buffer.rs => vertex_buffer/mod.rs} (96%) create mode 100644 format/src/flver/vertex_buffer/normalization.rs diff --git a/format/src/flver/accessor.rs b/format/src/flver/accessor.rs deleted file mode 100644 index dc9eed5..0000000 --- a/format/src/flver/accessor.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::{marker::PhantomData, mem::size_of}; - -use bytemuck::Pod; - -pub enum VertexAttributeAccessor<'a> { - Float2(VertexAttributeIter<'a, [f32; 2]>), - Float3(VertexAttributeIter<'a, [f32; 3]>), - Float4(VertexAttributeIter<'a, [f32; 4]>), - Byte4A(VertexAttributeIter<'a, [u8; 4]>), - Byte4B(VertexAttributeIter<'a, [u8; 4]>), - Short2ToFloat2(VertexAttributeIter<'a, [u16; 2]>), - Byte4C(VertexAttributeIter<'a, [u8; 4]>), - UV(VertexAttributeIter<'a, [f32; 2]>), - // TODO: get the last 2 components of this - UVPair(VertexAttributeIter<'a, [f32; 2]>), - Short4ToFloat4A(VertexAttributeIter<'a, [u16; 4]>), - Short4ToFloat4B(VertexAttributeIter<'a, [u16; 4]>), -} - -pub struct VertexAttributeIter<'a, T: Pod> { - buffer: &'a [u8], - attribute_data_offset: usize, - attribute_data_end: usize, - vertex_size: usize, - _phantom: PhantomData, -} - -// TODO: this doesn't support endian sensitive reading like the rest of the FLVER parser. -impl<'a, T: Pod> VertexAttributeIter<'a, T> { - pub fn new( - buffer: &'a [u8], - vertex_size: usize, - vertex_offset: usize, - ) -> VertexAttributeIter<'a, T> { - let attribute_data_offset = vertex_offset; - let attribute_data_end = attribute_data_offset + size_of::(); - - Self { - buffer, - attribute_data_offset, - attribute_data_end, - vertex_size, - _phantom: Default::default(), - } - } -} - -impl<'a, T: Pod> ExactSizeIterator for VertexAttributeIter<'a, T> {} -impl<'a, T: Pod> Iterator for VertexAttributeIter<'a, T> { - type Item = T; - - fn next(&mut self) -> Option { - if self.buffer.is_empty() { - return None; - } - - let attribute_byte_data = &self.buffer[self.attribute_data_offset..self.attribute_data_end]; - let data: &T = bytemuck::from_bytes(attribute_byte_data); - - self.buffer = &self.buffer[self.vertex_size..]; - - Some(*data) - } - - fn size_hint(&self) -> (usize, Option) { - let remaining = self.buffer.len() / self.vertex_size; - (remaining, Some(remaining)) - } -} diff --git a/format/src/flver/mod.rs b/format/src/flver/mod.rs index bb1055f..35b4e68 100644 --- a/format/src/flver/mod.rs +++ b/format/src/flver/mod.rs @@ -6,11 +6,13 @@ use std::{ use byteorder::{ByteOrder, LE}; use header::FlverHeader; +use vertex_buffer::accessor::{ + VertexAttributeAccessor as Accessor, VertexAttributeAccessor, VertexAttributeIter as Iter, +}; use zerocopy::{FromBytes, Ref, U16, U32}; use crate::{ flver::{ - accessor::VertexAttributeAccessor, bone::Bone, dummy::Dummy, face_set::{FaceSet, FaceSetIndices}, @@ -24,7 +26,6 @@ use crate::{ io_ext::ReadFormatsExt, }; -pub mod accessor; pub mod bone; pub mod dummy; pub mod face_set; @@ -118,12 +119,9 @@ impl<'a, O: ByteOrder + 'static> FlverInner<'a, O> { buffer: &VertexBuffer, attribute: &VertexBufferAttribute, ) -> VertexAttributeAccessor<'a> { - use crate::flver::{ - accessor::{VertexAttributeAccessor as Accessor, VertexAttributeIter as Iter}, - reader::VertexAttributeFormat::{ - Byte4A, Byte4B, Byte4C, Float2, Float3, Float4, Short2ToFloat2, Short4ToFloat4A, - Short4ToFloat4B, UVPair, UV, - }, + use crate::flver::reader::VertexAttributeFormat::{ + Byte4A, Byte4B, Byte4C, Float2, Float3, Float4, Short2ToFloat2, Short4ToFloat4A, + Short4ToFloat4B, UVPair, UV, }; let buffer_offset = buffer.buffer_offset.get() as usize; diff --git a/format/src/flver/vertex_buffer/accessor.rs b/format/src/flver/vertex_buffer/accessor.rs new file mode 100644 index 0000000..0361c5d --- /dev/null +++ b/format/src/flver/vertex_buffer/accessor.rs @@ -0,0 +1,84 @@ +use std::{array, marker::PhantomData, mem::size_of}; + +use bytemuck::Pod; + +use crate::flver::vertex_buffer::normalization::{NoNormalization, VertexAttributeNormalization}; + +pub enum VertexAttributeAccessor<'a> { + Float2(VertexAttributeIter<'a, f32, 2>), + Float3(VertexAttributeIter<'a, f32, 3>), + Float4(VertexAttributeIter<'a, f32, 4>), + Byte4A(VertexAttributeIter<'a, u8, 4>), + Byte4B(VertexAttributeIter<'a, u8, 4>), + Short2ToFloat2(VertexAttributeIter<'a, u16, 2>), + Byte4C(VertexAttributeIter<'a, u8, 4>), + UV(VertexAttributeIter<'a, f32, 2>), + // TODO: get the last 2 components of this + UVPair(VertexAttributeIter<'a, f32, 2>), + Short4ToFloat4A(VertexAttributeIter<'a, u16, 4>), + Short4ToFloat4B(VertexAttributeIter<'a, u16, 4>), +} + +pub struct VertexAttributeIter< + 'a, + T: Pod, + const L: usize, + N: VertexAttributeNormalization = NoNormalization, +> { + buffer: &'a [u8], + attribute_data_offset: usize, + attribute_data_end: usize, + vertex_size: usize, + _value: PhantomData, + _normalization: PhantomData, +} + +// TODO: this doesn't support endian sensitive reading like the rest of the FLVER parser. +impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization> VertexAttributeIter<'a, T, L, N> { + pub fn new( + buffer: &'a [u8], + vertex_size: usize, + vertex_offset: usize, + ) -> VertexAttributeIter<'a, T, L, N> { + let attribute_data_offset = vertex_offset; + let attribute_data_end = attribute_data_offset + size_of::() * L; + + Self { + buffer, + attribute_data_offset, + attribute_data_end, + vertex_size, + _value: PhantomData, + _normalization: PhantomData, + } + } +} + +impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization> ExactSizeIterator + for VertexAttributeIter<'a, T, L, N> +{ +} +impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization> Iterator + for VertexAttributeIter<'a, T, L, N> +{ + type Item = [N::Output; L]; + + fn next(&mut self) -> Option { + if self.buffer.is_empty() { + return None; + } + + let attribute_byte_data = &self.buffer[self.attribute_data_offset..self.attribute_data_end]; + let data: &[T] = bytemuck::cast_slice(attribute_byte_data); + let output: [N::Output; L] = array::from_fn(|index| N::normalize(&data[index])); + + self.buffer = &self.buffer[self.vertex_size..]; + + Some(output) + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = self.buffer.len() / self.vertex_size; + (remaining, Some(remaining)) + } +} diff --git a/format/src/flver/vertex_buffer.rs b/format/src/flver/vertex_buffer/mod.rs similarity index 96% rename from format/src/flver/vertex_buffer.rs rename to format/src/flver/vertex_buffer/mod.rs index 2781e89..4b4fa60 100644 --- a/format/src/flver/vertex_buffer.rs +++ b/format/src/flver/vertex_buffer/mod.rs @@ -3,6 +3,9 @@ use zerocopy::{FromBytes, FromZeroes, U32}; use crate::{flver::header::FlverHeaderPart, io_ext::zerocopy::Padding}; +pub mod accessor; +mod normalization; + #[derive(Debug, FromBytes, FromZeroes)] #[allow(unused)] #[repr(packed)] diff --git a/format/src/flver/vertex_buffer/normalization.rs b/format/src/flver/vertex_buffer/normalization.rs new file mode 100644 index 0000000..2b8e332 --- /dev/null +++ b/format/src/flver/vertex_buffer/normalization.rs @@ -0,0 +1,45 @@ +use std::marker::PhantomData; + +pub trait VertexAttributeNormalization { + type Input; + type Output; + + fn normalize(input: &Self::Input) -> Self::Output; +} + +pub struct NoNormalization { + _phantom: PhantomData, +} + +impl VertexAttributeNormalization for NoNormalization { + type Input = T; + type Output = T; + + fn normalize(input: &Self::Input) -> Self::Output { + *input + } +} + +/// Normalize an unsigned 4-bit value to a range of [0, 1] with 128 possible values. +pub struct UNorm4; + +impl VertexAttributeNormalization for UNorm4 { + type Input = u8; + type Output = f32; + + fn normalize(input: &Self::Input) -> Self::Output { + *input as f32 / 127.0 + } +} + +/// Normalize an unsigned 8-bit value to a range of [0,1] with 256 possible values. +pub struct UNorm8; + +impl VertexAttributeNormalization for UNorm8 { + type Input = u8; + type Output = f32; + + fn normalize(input: &Self::Input) -> Self::Output { + *input as f32 / 255.0 + } +} diff --git a/viewer/src/flver/asset.rs b/viewer/src/flver/asset.rs index fc2879b..213f5f0 100644 --- a/viewer/src/flver/asset.rs +++ b/viewer/src/flver/asset.rs @@ -11,10 +11,10 @@ use bevy::{ }; use byteorder::LE; use format::flver::{ - accessor::VertexAttributeAccessor, face_set::FaceSetIndices, mesh::Mesh as FlverMesh, reader::{VertexAttributeFormat, VertexAttributeSemantic, FLVER}, + vertex_buffer::accessor::VertexAttributeAccessor, Flver, }; From a3895890fee13351521a0bc6e0ca27a5e493cba7 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Thu, 29 Feb 2024 10:49:33 +0000 Subject: [PATCH 2/4] Add UNorm/SNorm normalization traits --- format/src/flver/mod.rs | 8 +++---- format/src/flver/vertex_buffer/accessor.rs | 13 ++++++---- .../src/flver/vertex_buffer/normalization.rs | 24 ++++++++++++------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/format/src/flver/mod.rs b/format/src/flver/mod.rs index 35b4e68..d7f6a2c 100644 --- a/format/src/flver/mod.rs +++ b/format/src/flver/mod.rs @@ -135,10 +135,10 @@ impl<'a, O: ByteOrder + 'static> FlverInner<'a, O> { Float3 => Accessor::Float3(Iter::new(data, vertex_size, vertex_offset)), Float2 => Accessor::Float2(Iter::new(data, vertex_size, vertex_offset)), Float4 => Accessor::Float4(Iter::new(data, vertex_size, vertex_offset)), - Byte4A => Accessor::Byte4A(Iter::new(data, vertex_size, vertex_offset)), - Byte4B => Accessor::Byte4B(Iter::new(data, vertex_size, vertex_offset)), - Short2ToFloat2 => Accessor::Short2ToFloat2(Iter::new(data, vertex_size, vertex_offset)), - Byte4C => Accessor::Byte4C(Iter::new(data, vertex_size, vertex_offset)), + Byte4A => Accessor::UNorm8x4(Iter::new(data, vertex_size, vertex_offset)), + Byte4B => Accessor::UNorm4x4(Iter::new(data, vertex_size, vertex_offset)), + Short2ToFloat2 => Accessor::UNorm16x2(Iter::new(data, vertex_size, vertex_offset)), + Byte4C => Accessor::SNorm8x4(Iter::new(data, vertex_size, vertex_offset)), UV => Accessor::UV(Iter::new(data, vertex_size, vertex_offset)), UVPair => Accessor::UVPair(Iter::new(data, vertex_size, vertex_offset)), Short4ToFloat4A => { diff --git a/format/src/flver/vertex_buffer/accessor.rs b/format/src/flver/vertex_buffer/accessor.rs index 0361c5d..148059b 100644 --- a/format/src/flver/vertex_buffer/accessor.rs +++ b/format/src/flver/vertex_buffer/accessor.rs @@ -2,16 +2,19 @@ use std::{array, marker::PhantomData, mem::size_of}; use bytemuck::Pod; -use crate::flver::vertex_buffer::normalization::{NoNormalization, VertexAttributeNormalization}; +use crate::flver::vertex_buffer::normalization::{NoNormalization, SNorm, UNorm, VertexAttributeNormalization}; pub enum VertexAttributeAccessor<'a> { Float2(VertexAttributeIter<'a, f32, 2>), Float3(VertexAttributeIter<'a, f32, 3>), Float4(VertexAttributeIter<'a, f32, 4>), - Byte4A(VertexAttributeIter<'a, u8, 4>), - Byte4B(VertexAttributeIter<'a, u8, 4>), - Short2ToFloat2(VertexAttributeIter<'a, u16, 2>), - Byte4C(VertexAttributeIter<'a, u8, 4>), + UNorm8x4(VertexAttributeIter<'a, u8, 4, UNorm>), + UNorm4x4(VertexAttributeIter<'a, u8, 4, UNorm>), + UNorm16x2(VertexAttributeIter<'a, u16, 2, UNorm>), + UNorm16x4(VertexAttributeIter<'a, u16, 4, UNorm>), + SNorm8x4(VertexAttributeIter<'a, u8, 4, SNorm>), + SNorm16x4(VertexAttributeIter<'a, u16, 4, SNorm>), + SNorm16x2(VertexAttributeIter<'a, u16, 2, SNorm>), UV(VertexAttributeIter<'a, f32, 2>), // TODO: get the last 2 components of this UVPair(VertexAttributeIter<'a, f32, 2>), diff --git a/format/src/flver/vertex_buffer/normalization.rs b/format/src/flver/vertex_buffer/normalization.rs index 2b8e332..0848990 100644 --- a/format/src/flver/vertex_buffer/normalization.rs +++ b/format/src/flver/vertex_buffer/normalization.rs @@ -21,25 +21,31 @@ impl VertexAttributeNormalization for NoNormalization { } /// Normalize an unsigned 4-bit value to a range of [0, 1] with 128 possible values. -pub struct UNorm4; -impl VertexAttributeNormalization for UNorm4 { - type Input = u8; +/// Normalize a signed value to a range of [0,1] with N possible values. +pub struct SNorm + Copy, const N: usize> { + _value: PhantomData +} + +impl + Copy, const N: usize> VertexAttributeNormalization for SNorm { + type Input = T; type Output = f32; fn normalize(input: &Self::Input) -> Self::Output { - *input as f32 / 127.0 + ((*input).into() - N as f32) / N as f32 } } -/// Normalize an unsigned 8-bit value to a range of [0,1] with 256 possible values. -pub struct UNorm8; +/// Normalize an unsigned value to a range of [0,1] with N possible values. +pub struct UNorm + Copy, const N: usize> { + _value: PhantomData +} -impl VertexAttributeNormalization for UNorm8 { - type Input = u8; +impl + Copy, const N: usize> VertexAttributeNormalization for UNorm { + type Input = T; type Output = f32; fn normalize(input: &Self::Input) -> Self::Output { - *input as f32 / 255.0 + (*input).into() / N as f32 } } From b4f28a7cf0155dbb9cbeb8b505511d04456143f3 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Fri, 1 Mar 2024 19:33:14 +0000 Subject: [PATCH 3/4] Map format_id + semantic_id to a valid VertexFormat --- format/src/flver/mod.rs | 34 +++----- format/src/flver/reader.rs | 80 +------------------ format/src/flver/vertex_buffer/accessor.rs | 4 +- format/src/flver/vertex_buffer/mod.rs | 59 +++++++++++++- .../src/flver/vertex_buffer/normalization.rs | 4 +- viewer/src/flver/asset.rs | 13 +-- 6 files changed, 79 insertions(+), 115 deletions(-) diff --git a/format/src/flver/mod.rs b/format/src/flver/mod.rs index d7f6a2c..e413974 100644 --- a/format/src/flver/mod.rs +++ b/format/src/flver/mod.rs @@ -19,7 +19,6 @@ use crate::{ header::FlverHeaderPart, material::Material, mesh::Mesh, - reader::VertexAttributeFormat, texture::Texture, vertex_buffer::{VertexBuffer, VertexBufferAttribute, VertexBufferLayout}, }, @@ -118,12 +117,7 @@ impl<'a, O: ByteOrder + 'static> FlverInner<'a, O> { &self, buffer: &VertexBuffer, attribute: &VertexBufferAttribute, - ) -> VertexAttributeAccessor<'a> { - use crate::flver::reader::VertexAttributeFormat::{ - Byte4A, Byte4B, Byte4C, Float2, Float3, Float4, Short2ToFloat2, Short4ToFloat4A, - Short4ToFloat4B, UVPair, UV, - }; - + ) -> Option> { let buffer_offset = buffer.buffer_offset.get() as usize; let buffer_length = buffer.buffer_length.get() as usize; @@ -131,24 +125,16 @@ impl<'a, O: ByteOrder + 'static> FlverInner<'a, O> { let vertex_size = buffer.vertex_size.get() as usize; let vertex_offset = attribute.struct_offset.get() as usize; - match VertexAttributeFormat::from(attribute.format_id.get()) { - Float3 => Accessor::Float3(Iter::new(data, vertex_size, vertex_offset)), - Float2 => Accessor::Float2(Iter::new(data, vertex_size, vertex_offset)), - Float4 => Accessor::Float4(Iter::new(data, vertex_size, vertex_offset)), - Byte4A => Accessor::UNorm8x4(Iter::new(data, vertex_size, vertex_offset)), - Byte4B => Accessor::UNorm4x4(Iter::new(data, vertex_size, vertex_offset)), - Short2ToFloat2 => Accessor::UNorm16x2(Iter::new(data, vertex_size, vertex_offset)), - Byte4C => Accessor::SNorm8x4(Iter::new(data, vertex_size, vertex_offset)), - UV => Accessor::UV(Iter::new(data, vertex_size, vertex_offset)), - UVPair => Accessor::UVPair(Iter::new(data, vertex_size, vertex_offset)), - Short4ToFloat4A => { - Accessor::Short4ToFloat4A(Iter::new(data, vertex_size, vertex_offset)) - } - Short4ToFloat4B => { - Accessor::Short4ToFloat4B(Iter::new(data, vertex_size, vertex_offset)) - } + use vertex_buffer::VertexFormat::*; + + attribute.format().map(|format| match format { + Float32x3 => Accessor::Float3(Iter::new(data, vertex_size, vertex_offset)), + Float32x2 => Accessor::Float2(Iter::new(data, vertex_size, vertex_offset)), + Float32x4 => Accessor::Float4(Iter::new(data, vertex_size, vertex_offset)), + Unorm8x4 => Accessor::UNorm8x4(Iter::new(data, vertex_size, vertex_offset)), + Snorm8x4 => Accessor::SNorm8x4(Iter::new(data, vertex_size, vertex_offset)), _ => unimplemented!(), - } + }) } fn parse_no_verify(bytes: &'a [u8]) -> Option { diff --git a/format/src/flver/reader.rs b/format/src/flver/reader.rs index e1d1883..9bed843 100644 --- a/format/src/flver/reader.rs +++ b/format/src/flver/reader.rs @@ -588,82 +588,6 @@ pub enum VertexAttributeFormat { Byte4E = 0x2F, EdgeCompressed = 0xF0, } - -impl VertexAttributeFormat { - pub fn datum_size(&self) -> usize { - match self { - VertexAttributeFormat::Float2 - | VertexAttributeFormat::Float3 - | VertexAttributeFormat::Float4 - | VertexAttributeFormat::UV - | VertexAttributeFormat::UVPair => 4, - VertexAttributeFormat::Byte4A - | VertexAttributeFormat::Byte4B - | VertexAttributeFormat::Byte4C - | VertexAttributeFormat::Byte4E => 1, - VertexAttributeFormat::Short2ToFloat2 - | VertexAttributeFormat::ShortBoneIndices - | VertexAttributeFormat::Short4ToFloat4A - | VertexAttributeFormat::Short4ToFloat4B => 2, - _ => unimplemented!(), - } - } - pub fn dimensions(&self) -> usize { - match self { - VertexAttributeFormat::Float2 => 2, - VertexAttributeFormat::Float3 => 3, - VertexAttributeFormat::Float4 => 4, - VertexAttributeFormat::Byte4A => 4, - VertexAttributeFormat::Byte4B => 4, - VertexAttributeFormat::Short2ToFloat2 => 2, - VertexAttributeFormat::Byte4C => 4, - VertexAttributeFormat::UV => 2, - VertexAttributeFormat::UVPair => 4, - VertexAttributeFormat::ShortBoneIndices => 4, - VertexAttributeFormat::Short4ToFloat4A => 4, - VertexAttributeFormat::Short4ToFloat4B => 4, - VertexAttributeFormat::Byte4E => 4, - VertexAttributeFormat::EdgeCompressed => unimplemented!(), - } - } -} - -pub enum VertexAttributeDimensions { - Scalar, - Vec2, - Vec3, - Vec4, -} - -pub enum VertexAttributeDataType { - F32, - U32, - U16, - I16, -} - -impl From for VertexAttributeFormat { - fn from(value: u32) -> Self { - match value { - 0x1 => Self::Float2, - 0x2 => Self::Float3, - 0x3 => Self::Float4, - 0x10 => Self::Byte4A, - 0x11 => Self::Byte4B, - 0x12 => Self::Short2ToFloat2, - 0x13 => Self::Byte4C, - 0x15 => Self::UV, - 0x16 => Self::UVPair, - 0x18 => Self::ShortBoneIndices, - 0x1A => Self::Short4ToFloat4A, - 0x2E => Self::Short4ToFloat4B, - 0x2F => Self::Byte4E, - 0xF0 => Self::EdgeCompressed, - _ => panic!("Unknown storage type {}", value), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq)] pub enum VertexAttributeSemantic { Position, @@ -696,7 +620,7 @@ impl From for VertexAttributeSemantic { pub struct FLVERBufferLayoutMember { pub unk0: u32, pub struct_offset: u32, - pub format: VertexAttributeFormat, + pub format: u32, pub semantic: VertexAttributeSemantic, pub index: u32, } @@ -709,7 +633,7 @@ impl FLVERPartReader for FLVERBufferLayoutMember { Ok(Self { unk0: r.read_u32::()?, struct_offset: r.read_u32::()?, - format: r.read_u32::()?.into(), + format: r.read_u32::()?, semantic: r.read_u32::()?.into(), index: r.read_u32::()?, }) diff --git a/format/src/flver/vertex_buffer/accessor.rs b/format/src/flver/vertex_buffer/accessor.rs index 148059b..612a30a 100644 --- a/format/src/flver/vertex_buffer/accessor.rs +++ b/format/src/flver/vertex_buffer/accessor.rs @@ -2,7 +2,9 @@ use std::{array, marker::PhantomData, mem::size_of}; use bytemuck::Pod; -use crate::flver::vertex_buffer::normalization::{NoNormalization, SNorm, UNorm, VertexAttributeNormalization}; +use crate::flver::vertex_buffer::normalization::{ + NoNormalization, SNorm, UNorm, VertexAttributeNormalization, +}; pub enum VertexAttributeAccessor<'a> { Float2(VertexAttributeIter<'a, f32, 2>), diff --git a/format/src/flver/vertex_buffer/mod.rs b/format/src/flver/vertex_buffer/mod.rs index 4b4fa60..99af827 100644 --- a/format/src/flver/vertex_buffer/mod.rs +++ b/format/src/flver/vertex_buffer/mod.rs @@ -1,7 +1,10 @@ use byteorder::ByteOrder; use zerocopy::{FromBytes, FromZeroes, U32}; -use crate::{flver::header::FlverHeaderPart, io_ext::zerocopy::Padding}; +use crate::{ + flver::{header::FlverHeaderPart, reader::VertexAttributeSemantic}, + io_ext::zerocopy::Padding, +}; pub mod accessor; mod normalization; @@ -43,4 +46,58 @@ pub struct VertexBufferAttribute { pub index: U32, } +impl VertexBufferAttribute { + pub fn format(&self) -> Option { + use VertexAttributeSemantic::*; + use VertexFormat::*; + + let format = match ( + VertexAttributeSemantic::from(self.semantic_id.get()), + self.format_id.get(), + ) { + (Position | UV, 0x02) => Float32x3, + (Position | UV, 0x03) => Float32x4, + (UV, 0x01) => Float32x2, + (UV, 0x10 | 0x11 | 0x12 | 0x13 | 0x15) => Sscale16x2, + (UV, 0x16) => Sscale16x4, + (UV, 0x11A | 0x2E) => Sscale16x4, + (Normal, 0x04) => Float32x4, + (Normal, 0x10 | 0x11 | 0x13 | 0x2F) => Snorm8x4, + (Normal, 0x12) => Snorm8x4, // soulstruct says unorm clamped to 127 + (Normal, 0x1A) => Snorm16x4, + (Normal, 0x2E) => Snorm16x4, // soulstruct says unorm clamped to 127, + (BoneWeights, 0x10) => Snorm8x4, + (BoneWeights, 0x13) => Unorm8x4, + (BoneWeights, 0x16 | 0x1A) => Snorm16x4, + (BoneIndices, 0x11 | 0x24) => Uint8x4, + (BoneIndices, 0x18) => Sint16x4, + _ => return None, + }; + + Some(format) + } +} + +pub enum VertexFormat { + Float32x2, + Float32x3, + Float32x4, + Unorm8x4, + Snorm8x4, + Snorm16x4, + Uint8x4, + Sint16x4, + Sscale16x2, + Sscale16x4, +} + +// UVs: +// +// 0x01: 2 floats +// 0x02: 3 floats (only 2 components used) +// 0x03: 2 floats, 2 floats +// 0x10, 0x11, 0x12, 0x13, 0x15: 2 signed shorts -> float (cast to float, take UV factor into +// account) 0x16: 4 signed shorts -> float (cast to float, take UV factor into account) +// 0x1A, 0x2E: 4 signed shorts -> float (cast to float, take UV factor into account) (only 2 +// components used) impl FlverHeaderPart for VertexBufferAttribute {} diff --git a/format/src/flver/vertex_buffer/normalization.rs b/format/src/flver/vertex_buffer/normalization.rs index 0848990..14845fb 100644 --- a/format/src/flver/vertex_buffer/normalization.rs +++ b/format/src/flver/vertex_buffer/normalization.rs @@ -24,7 +24,7 @@ impl VertexAttributeNormalization for NoNormalization { /// Normalize a signed value to a range of [0,1] with N possible values. pub struct SNorm + Copy, const N: usize> { - _value: PhantomData + _value: PhantomData, } impl + Copy, const N: usize> VertexAttributeNormalization for SNorm { @@ -38,7 +38,7 @@ impl + Copy, const N: usize> VertexAttributeNormalization for SNorm /// Normalize an unsigned value to a range of [0,1] with N possible values. pub struct UNorm + Copy, const N: usize> { - _value: PhantomData + _value: PhantomData, } impl + Copy, const N: usize> VertexAttributeNormalization for UNorm { diff --git a/viewer/src/flver/asset.rs b/viewer/src/flver/asset.rs index 213f5f0..fd89def 100644 --- a/viewer/src/flver/asset.rs +++ b/viewer/src/flver/asset.rs @@ -2,7 +2,6 @@ use std::{error::Error, io::Cursor}; use bevy::{ asset::{io::Reader, Asset, AssetLoader, AsyncReadExt, BoxedFuture, Handle, LoadContext}, - log::warn, prelude::{Mesh, TypePath}, render::{ mesh::{Indices, PrimitiveTopology, VertexAttributeValues}, @@ -13,7 +12,7 @@ use byteorder::LE; use format::flver::{ face_set::FaceSetIndices, mesh::Mesh as FlverMesh, - reader::{VertexAttributeFormat, VertexAttributeSemantic, FLVER}, + reader::{VertexAttributeSemantic, FLVER}, vertex_buffer::accessor::VertexAttributeAccessor, Flver, }; @@ -105,9 +104,10 @@ fn load_mesh(flver: &Flver, flver_mesh: &FlverMesh) -> Mesh { for member in layout_members { use format::flver::reader::VertexAttributeSemantic::*; - let accessor = flver.vertex_attribute_accessor(buffer, member); let semantic = VertexAttributeSemantic::from(member.semantic_id.get()); - let format = VertexAttributeFormat::from(member.format_id.get()); + let Some(accessor) = flver.vertex_attribute_accessor(buffer, member) else { + continue; + }; let (attribute, values) = match (semantic, accessor) { (Position, VertexAttributeAccessor::Float3(it)) => ( @@ -123,11 +123,6 @@ fn load_mesh(flver: &Flver, flver_mesh: &FlverMesh) -> Mesh { VertexAttributeValues::Float32x2(it.collect()), ), _ => { - warn!( - "Vertex Attribute {:#?} and format {:#?} is currently unsupported", - semantic, format - ); - continue; } }; From 054d0eff8ea8a297b5179ba43cdddd6aa24f8765 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Tue, 5 Mar 2024 19:55:05 +0000 Subject: [PATCH 4/4] Disable normalization --- format/src/flver/vertex_buffer/accessor.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/format/src/flver/vertex_buffer/accessor.rs b/format/src/flver/vertex_buffer/accessor.rs index 612a30a..b7e040d 100644 --- a/format/src/flver/vertex_buffer/accessor.rs +++ b/format/src/flver/vertex_buffer/accessor.rs @@ -57,6 +57,17 @@ impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization> VertexAttribut _normalization: PhantomData, } } + + pub fn no_norm(self) -> VertexAttributeIter<'a, T, L, NoNormalization> { + let Self { + buffer, + vertex_size, + attribute_data_offset, + .. + } = self; + + VertexAttributeIter::new(buffer, vertex_size, attribute_data_offset) + } } impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization> ExactSizeIterator