implement lod fixups

This commit is contained in:
Robin Appelman 2022-03-17 23:06:34 +01:00
commit 28d8f5dee5
3 changed files with 41 additions and 31 deletions

View file

@ -108,6 +108,24 @@ fn index_range(index: i32, count: i32, size: usize) -> impl Iterator<Item = usiz
.map(move |i| index as usize + i) .map(move |i| index as usize + i)
} }
fn read_relative_iter<'a, T: ReadRelative, I: 'a + Iterator<Item = usize>>(
data: &'a [u8],
indexes: I,
) -> impl Iterator<Item = Result<T, ModelError>> + 'a
where
<<T as ReadRelative>::Header as BinRead>::Args: Default,
{
indexes.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: type_name::<T>(),
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
T::read(data, header)
})
}
fn read_relative<T: ReadRelative, I: Iterator<Item = usize>>( fn read_relative<T: ReadRelative, I: Iterator<Item = usize>>(
data: &[u8], data: &[u8],
indexes: I, indexes: I,
@ -115,17 +133,7 @@ fn read_relative<T: ReadRelative, I: Iterator<Item = usize>>(
where where
<<T as ReadRelative>::Header as BinRead>::Args: Default, <<T as ReadRelative>::Header as BinRead>::Args: Default,
{ {
indexes read_relative_iter(data, indexes).collect()
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: type_name::<T>(),
offset: index,
})?;
let mut reader = Cursor::new(data);
let header = reader.read_le()?;
T::read(data, header)
})
.collect()
} }
trait ReadRelative: Sized { trait ReadRelative: Sized {

View file

@ -1,7 +1,7 @@
mod raw; mod raw;
use crate::vvd::raw::VvdHeader; use crate::vvd::raw::{VertexFileFixup, VvdHeader};
use crate::ModelError; use crate::{read_relative, read_relative_iter, ModelError};
use binrw::BinReaderExt; use binrw::BinReaderExt;
pub use raw::{BoneWeight, Tangent, Vertex}; pub use raw::{BoneWeight, Tangent, Vertex};
use std::io::Cursor; use std::io::Cursor;
@ -18,20 +18,21 @@ impl Vvd {
pub fn read(data: &[u8]) -> Result<Self> { pub fn read(data: &[u8]) -> Result<Self> {
let mut reader = Cursor::new(data); let mut reader = Cursor::new(data);
let header: VvdHeader = reader.read_le()?; let header: VvdHeader = reader.read_le()?;
Ok(Vvd { let source_vertices = read_relative(data, header.vertex_indexes(0).unwrap())?;
vertices: header let vertices = if !header.has_fixups() {
.vertex_indexes(0) source_vertices
.unwrap() } else {
.map(|index| { let mut vertices = Vec::new();
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds { for fixup in read_relative_iter::<'_, VertexFileFixup, _>(data, header.fixup_indexes())
data: "Vertex", {
offset: index, let fixup = fixup?;
})?; vertices.extend_from_slice(
let mut reader = Cursor::new(data); &source_vertices[fixup.source_vertex_id as usize
Ok(reader.read_le()?) ..(fixup.source_vertex_id + fixup.vertex_count) as usize],
}) );
.collect::<Result<_>>()?, }
header, vertices
}) };
Ok(Vvd { vertices, header })
} }
} }

View file

@ -24,10 +24,11 @@ impl VvdHeader {
) )
} }
pub fn has_fixups(&self) -> bool {
self.fixup_count > 0
}
pub fn vertex_indexes(&self, lod: i32) -> Option<impl Iterator<Item = usize>> { pub fn vertex_indexes(&self, lod: i32) -> Option<impl Iterator<Item = usize>> {
if lod > 0 && lod > self.fixup_count {
todo!("lod fixup not supported")
}
if lod < self.lod_count { if lod < self.lod_count {
Some(index_range( Some(index_range(
self.vertex_index, self.vertex_index,