mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
better vertex indices
This commit is contained in:
parent
88bcdb35e7
commit
3649ffd9b2
7 changed files with 75 additions and 56 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
29
src/lib.rs
29
src/lib.rs
|
|
@ -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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue