better vertex indices

This commit is contained in:
Robin Appelman 2022-03-11 22:53:57 +01:00
commit 3649ffd9b2
7 changed files with 75 additions and 56 deletions

View file

@ -10,6 +10,7 @@ binrw = "0.8.0"
thiserror = "1.0.30" thiserror = "1.0.30"
static_assertions = "1.1.0" static_assertions = "1.1.0"
bitflags = "1.0.4" bitflags = "1.0.4"
itertools = "0.10.3"
[dev-dependencies] [dev-dependencies]
three-d = "0.10.2" three-d = "0.10.2"

View file

@ -1,6 +1,5 @@
use std::env::args_os; use std::env::args_os;
use std::fs; use std::fs;
use std::fs::read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use thiserror::Error; use thiserror::Error;
use three_d::*; use three_d::*;
@ -17,8 +16,6 @@ enum Error {
Mdl(#[from] vmdl::ModelError), Mdl(#[from] vmdl::ModelError),
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
#[error("{0}")]
Other(&'static str),
} }
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
@ -32,7 +29,7 @@ fn main() -> Result<(), Error> {
let window = Window::new(WindowSettings { let window = Window::new(WindowSettings {
title: path.display().to_string(), title: path.display().to_string(),
min_size: (512, 512), min_size: (512, 512),
max_size: Some((1280, 720)), max_size: Some((1920, 1080)),
..Default::default() ..Default::default()
}) })
.unwrap(); .unwrap();
@ -53,7 +50,7 @@ fn main() -> Result<(), Error> {
let mut control = OrbitControl::new(*camera.target(), 1.0, 100.0); let mut control = OrbitControl::new(*camera.target(), 1.0, 100.0);
let mut gui = three_d::GUI::new(&context).unwrap(); let mut gui = three_d::GUI::new(&context).unwrap();
let mut cpu_mesh = model_to_mesh(&model); let cpu_mesh = model_to_mesh(&model);
let material = PhysicalMaterial { let material = PhysicalMaterial {
albedo: Color { albedo: Color {
r: 128, r: 128,
@ -228,25 +225,26 @@ const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
fn model_to_mesh(model: &Model) -> CPUMesh { fn model_to_mesh(model: &Model) -> CPUMesh {
let positions: Vec<f32> = model let positions: Vec<f32> = model
.vertex_strips() .vertices()
.flat_map(|mut strip| { .iter()
let mut a = strip.next().unwrap(); .flat_map(|vertex| vertex.position.iter().map(|pos| pos * UNIT_SCALE * 10.0))
let mut b = strip.next().unwrap();
strip
.flat_map(move |c| {
let tri = [a, b, c];
a = b;
b = c;
tri
})
.flat_map(|vec| vec.iter())
})
.collect(); .collect();
let normals: Vec<f32> = model
.vertices()
.iter()
.flat_map(|vertex| vertex.normal.iter())
.collect();
let indices = Indices::U32(
model
.vertex_strip_indices()
.flat_map(|strip| strip.map(|index| index as u32))
.collect(),
);
let mut mesh = CPUMesh { CPUMesh {
positions, positions,
normals: Some(normals),
indices: Some(indices),
..Default::default() ..Default::default()
}; }
mesh.compute_normals();
mesh
} }

View file

@ -7,7 +7,7 @@ use std::ops::Deref;
/// reference parts from other structures in the mdl file /// reference parts from other structures in the mdl file
#[derive(Debug)] #[derive(Debug)]
pub struct Handle<'a, T> { pub struct Handle<'a, T> {
mdl: &'a Mdl, _mdl: &'a Mdl,
data: &'a T, data: &'a T,
} }

View file

@ -7,7 +7,7 @@ pub mod vvd;
use crate::mdl::Mdl; use crate::mdl::Mdl;
use crate::vtx::Vtx; use crate::vtx::Vtx;
use crate::vvd::Vvd; use crate::vvd::{Vertex, Vvd};
use binrw::{BinRead, BinReaderExt}; use binrw::{BinRead, BinReaderExt};
pub use error::*; pub use error::*;
pub use handle::Handle; pub use handle::Handle;
@ -16,6 +16,7 @@ use std::any::type_name;
use std::io::Cursor; use std::io::Cursor;
pub struct Model { pub struct Model {
#[allow(dead_code)]
mdl: Mdl, mdl: Mdl,
vtx: Vtx, vtx: Vtx,
vvd: Vvd, vvd: Vvd,
@ -26,7 +27,16 @@ impl Model {
Model { mdl, vtx, vvd } Model { mdl, vtx, vvd }
} }
pub fn vertex_strips(&self) -> impl Iterator<Item = impl Iterator<Item = Vector> + '_> { pub fn vertex_strips(&self) -> impl Iterator<Item = impl Iterator<Item = &'_ Vertex> + '_> {
self.vertex_strip_indices()
.map(|strip| strip.map(|index| &self.vvd.vertices[index]))
}
pub fn vertices(&self) -> &[Vertex] {
&self.vvd.vertices
}
pub fn vertex_strip_indices(&self) -> impl Iterator<Item = impl Iterator<Item = usize> + '_> {
self.vtx self.vtx
.body_parts .body_parts
.iter() .iter()
@ -34,11 +44,16 @@ impl Model {
.flat_map(|model| model.lods.iter().next()) .flat_map(|model| model.lods.iter().next())
.flat_map(|lod| lod.meshes.iter()) .flat_map(|lod| lod.meshes.iter())
.flat_map(|mesh| mesh.strip_groups.iter()) .flat_map(|mesh| mesh.strip_groups.iter())
.map(|strip_group| { .flat_map(|strip_group| {
strip_group let group_indices = &strip_group.indices;
.indices let vertices = &strip_group.vertices;
.iter() strip_group.strips.iter().cloned().map(move |strip| {
.map(|index| self.vvd.vertices[(*index) as usize].position) strip
.indices()
.flat_map(|i| i)
.map(move |index| group_indices[index] as usize)
.map(move |index| vertices[index].original_mesh_vertex_id as usize)
})
}) })
} }
} }

View file

@ -2,9 +2,11 @@ mod raw;
use crate::ModelError; use crate::ModelError;
use binrw::BinReaderExt; use binrw::BinReaderExt;
use itertools::Either;
use raw::*; use raw::*;
pub use raw::{MeshFlags, StripFlags, StripGroupFlags, Vertex}; pub use raw::{MeshFlags, StripFlags, StripGroupFlags, Vertex};
use std::io::Cursor; use std::io::Cursor;
use std::ops::Range;
pub const MDL_VERSION: i32 = 7; pub const MDL_VERSION: i32 = 7;
@ -140,7 +142,6 @@ impl Mesh {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StripGroup { pub struct StripGroup {
// todo vertex indexes
// todo topologies // todo topologies
pub indices: Vec<u16>, pub indices: Vec<u16>,
pub vertices: Vec<Vertex>, pub vertices: Vec<Vertex>,
@ -192,27 +193,35 @@ impl StripGroup {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Strip { pub struct Strip {
// todo vertex indexes
// todo bone state changes // todo bone state changes
pub vertices: Vec<Vertex>, vertices: Range<usize>,
pub flags: StripFlags, pub flags: StripFlags,
indices: Range<usize>,
} }
impl Strip { impl Strip {
fn read(data: &[u8], header: StripHeader) -> Result<Self> { fn read(_data: &[u8], header: StripHeader) -> Result<Self> {
Ok(Strip { Ok(Strip {
vertices: header vertices: header.vertex_indexes(),
.vertex_indexes() indices: header.index_indexes(),
.map(|index| {
let data = data.get(index..).ok_or_else(|| ModelError::OutOfBounds {
data: "Vertex",
offset: index,
})?;
let mut reader = Cursor::new(data);
reader.read_le().map_err(ModelError::from)
})
.collect::<Result<_>>()?,
flags: header.flags, flags: header.flags,
}) })
} }
pub fn vertices(&self) -> impl Iterator<Item = usize> + 'static {
self.vertices.clone()
}
pub fn indices(&self) -> impl Iterator<Item = [usize; 3]> + 'static {
if self.flags.contains(StripFlags::IS_TRI_STRIP) {
let offset = self.indices.start;
Either::Left((0..self.indices.len()).map(move |i| {
let cw = i & 1;
let idx = offset + i;
[idx, idx + 1 - cw, idx + 2 - cw]
}))
} else {
Either::Right(self.indices.clone().step_by(3).map(|i| [i, i + 1, i + 2]))
}
}
} }

View file

@ -2,6 +2,7 @@ use crate::index_range;
use binrw::BinRead; use binrw::BinRead;
use bitflags::bitflags; use bitflags::bitflags;
use std::mem::size_of; use std::mem::size_of;
use std::ops::Range;
#[derive(Debug, Clone, BinRead)] #[derive(Debug, Clone, BinRead)]
pub struct VtxHeader { pub struct VtxHeader {
@ -169,18 +170,15 @@ bitflags! {
impl StripHeader { impl StripHeader {
/// Index into the VVD file vertexes /// Index into the VVD file vertexes
pub fn vertex_indexes(&self) -> impl Iterator<Item = usize> { pub fn vertex_indexes(&self) -> Range<usize> {
index_range( self.vertex_offset as usize..(self.vertex_offset + self.vertex_count) as usize
self.vertex_offset,
self.vertex_count,
size_of::<u16>(), // Vertex index from .VVD's vertex array
)
} }
pub fn index_indexes(&self) -> impl Iterator<Item = usize> { pub fn index_indexes(&self) -> Range<usize> {
index_range(self.index_offset, self.index_count, size_of::<Vertex>()) self.index_offset as usize..(self.index_offset + self.index_count) as usize
} }
#[allow(dead_code)]
pub fn bone_state_change_indexes(&self) -> impl Iterator<Item = usize> { pub fn bone_state_change_indexes(&self) -> impl Iterator<Item = usize> {
index_range( index_range(
self.bone_state_change_offset, self.bone_state_change_offset,

View file

@ -2,8 +2,6 @@ use crate::{index_range, Vector};
use binrw::BinRead; use binrw::BinRead;
use std::mem::size_of; use std::mem::size_of;
pub const MDL_VERSION: i32 = 7;
#[derive(Debug, Clone, BinRead)] #[derive(Debug, Clone, BinRead)]
pub struct VvdHeader { pub struct VvdHeader {
pub id: i32, pub id: i32,