Skip to content

Commit

Permalink
Merge pull request #16 from soulsmods/feat/flver-vertex-normalization
Browse files Browse the repository at this point in the history
Support for normalizing vertex attributes
  • Loading branch information
garyttierney authored Mar 5, 2024
2 parents af33f52 + 054d0ef commit 512d92f
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 229 deletions.
69 changes: 0 additions & 69 deletions format/src/flver/accessor.rs

This file was deleted.

42 changes: 13 additions & 29 deletions format/src/flver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ 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},
header::FlverHeaderPart,
material::Material,
mesh::Mesh,
reader::VertexAttributeFormat,
texture::Texture,
vertex_buffer::{VertexBuffer, VertexBufferAttribute, VertexBufferLayout},
},
io_ext::ReadFormatsExt,
};

pub mod accessor;
pub mod bone;
pub mod dummy;
pub mod face_set;
Expand Down Expand Up @@ -117,40 +117,24 @@ impl<'a, O: ByteOrder + 'static> FlverInner<'a, O> {
&self,
buffer: &VertexBuffer<O>,
attribute: &VertexBufferAttribute<O>,
) -> 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,
},
};

) -> Option<VertexAttributeAccessor<'a>> {
let buffer_offset = buffer.buffer_offset.get() as usize;
let buffer_length = buffer.buffer_length.get() as usize;

let data = &self.data[buffer_offset..buffer_offset + buffer_length];
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::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)),
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<Self> {
Expand Down
80 changes: 2 additions & 78 deletions format/src/flver/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u32> 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,
Expand Down Expand Up @@ -696,7 +620,7 @@ impl From<u32> for VertexAttributeSemantic {
pub struct FLVERBufferLayoutMember {
pub unk0: u32,
pub struct_offset: u32,
pub format: VertexAttributeFormat,
pub format: u32,
pub semantic: VertexAttributeSemantic,
pub index: u32,
}
Expand All @@ -709,7 +633,7 @@ impl FLVERPartReader for FLVERBufferLayoutMember {
Ok(Self {
unk0: r.read_u32::<LE>()?,
struct_offset: r.read_u32::<LE>()?,
format: r.read_u32::<LE>()?.into(),
format: r.read_u32::<LE>()?,
semantic: r.read_u32::<LE>()?.into(),
index: r.read_u32::<LE>()?,
})
Expand Down
43 changes: 0 additions & 43 deletions format/src/flver/vertex_buffer.rs

This file was deleted.

100 changes: 100 additions & 0 deletions format/src/flver/vertex_buffer/accessor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use std::{array, marker::PhantomData, mem::size_of};

use bytemuck::Pod;

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>),
UNorm8x4(VertexAttributeIter<'a, u8, 4, UNorm<u8, 255>>),
UNorm4x4(VertexAttributeIter<'a, u8, 4, UNorm<u8, 127>>),
UNorm16x2(VertexAttributeIter<'a, u16, 2, UNorm<u16, 32767>>),
UNorm16x4(VertexAttributeIter<'a, u16, 4, UNorm<u16, 32767>>),
SNorm8x4(VertexAttributeIter<'a, u8, 4, SNorm<u8, 127>>),
SNorm16x4(VertexAttributeIter<'a, u16, 4, SNorm<u16, 32767>>),
SNorm16x2(VertexAttributeIter<'a, u16, 2, SNorm<u16, 32767>>),
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<T>,
> {
buffer: &'a [u8],
attribute_data_offset: usize,
attribute_data_end: usize,
vertex_size: usize,
_value: PhantomData<T>,
_normalization: PhantomData<N>,
}

// 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::<T>() * L;

Self {
buffer,
attribute_data_offset,
attribute_data_end,
vertex_size,
_value: PhantomData,
_normalization: PhantomData,
}
}

pub fn no_norm(self) -> VertexAttributeIter<'a, T, L, NoNormalization<T>> {
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<Input = T>> ExactSizeIterator
for VertexAttributeIter<'a, T, L, N>
{
}
impl<'a, T: Pod, const L: usize, N: VertexAttributeNormalization<Input = T>> Iterator
for VertexAttributeIter<'a, T, L, N>
{
type Item = [N::Output; L];

fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
let remaining = self.buffer.len() / self.vertex_size;
(remaining, Some(remaining))
}
}
Loading

0 comments on commit 512d92f

Please sign in to comment.