mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-21 04:07:46 +00:00
Add support for reading shape morphs from MDL
This commit is contained in:
parent
840fb21ba0
commit
6bf60b0cfd
1 changed files with 57 additions and 6 deletions
63
src/model.rs
63
src/model.rs
|
@ -8,7 +8,7 @@ use binrw::{binrw, BinWrite, BinWriterExt};
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
use binrw::BinReaderExt;
|
use binrw::BinReaderExt;
|
||||||
use crate::{ByteBuffer, ByteSpan};
|
use crate::{ByteBuffer, ByteSpan};
|
||||||
use crate::model_vertex_declarations::{vertex_element_parser, VERTEX_ELEMENT_SIZE, vertex_element_writer, VertexDeclaration, VertexElement, VertexType, VertexUsage};
|
use crate::model_vertex_declarations::{vertex_element_parser, VERTEX_ELEMENT_SIZE, vertex_element_writer, VertexDeclaration, VertexType, VertexUsage};
|
||||||
|
|
||||||
pub const NUM_VERTICES: u32 = 17;
|
pub const NUM_VERTICES: u32 = 17;
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ struct TerrainShadowSubmesh {
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct Shape {
|
struct ShapeStruct {
|
||||||
string_offset: u32,
|
string_offset: u32,
|
||||||
shape_mesh_start_index: [u16; 3],
|
shape_mesh_start_index: [u16; 3],
|
||||||
shape_mesh_count: [u16; 3]
|
shape_mesh_count: [u16; 3]
|
||||||
|
@ -302,7 +302,7 @@ struct ModelData {
|
||||||
bone_tables: Vec<BoneTable>,
|
bone_tables: Vec<BoneTable>,
|
||||||
|
|
||||||
#[br(count = header.shape_count)]
|
#[br(count = header.shape_count)]
|
||||||
shapes: Vec<Shape>,
|
shapes: Vec<ShapeStruct>,
|
||||||
|
|
||||||
#[br(count = header.shape_mesh_count)]
|
#[br(count = header.shape_mesh_count)]
|
||||||
shape_meshes: Vec<ShapeMesh>,
|
shape_meshes: Vec<ShapeMesh>,
|
||||||
|
@ -376,6 +376,12 @@ pub struct SubMesh {
|
||||||
pub index_offset: u32
|
pub index_offset: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Shape {
|
||||||
|
pub name: String,
|
||||||
|
pub morphed_vertices: Vec<Vertex>
|
||||||
|
}
|
||||||
|
|
||||||
/// Corresponds to a "Mesh" in an LOD
|
/// Corresponds to a "Mesh" in an LOD
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Part {
|
pub struct Part {
|
||||||
|
@ -383,7 +389,8 @@ pub struct Part {
|
||||||
pub vertices: Vec<Vertex>,
|
pub vertices: Vec<Vertex>,
|
||||||
pub indices: Vec<u16>,
|
pub indices: Vec<u16>,
|
||||||
pub material_index: u16,
|
pub material_index: u16,
|
||||||
pub submeshes: Vec<SubMesh>
|
pub submeshes: Vec<SubMesh>,
|
||||||
|
pub shapes: Vec<Shape>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -398,7 +405,7 @@ pub struct MDL {
|
||||||
|
|
||||||
pub lods: Vec<Lod>,
|
pub lods: Vec<Lod>,
|
||||||
pub affected_bone_names: Vec<String>,
|
pub affected_bone_names: Vec<String>,
|
||||||
pub material_names: Vec<String>
|
pub material_names: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MDL {
|
impl MDL {
|
||||||
|
@ -606,7 +613,51 @@ impl MDL {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.push(Part { mesh_index: j, vertices, indices, material_index, submeshes });
|
let mut shapes = vec![];
|
||||||
|
|
||||||
|
for shape in &model.shapes {
|
||||||
|
// Adapted from https://github.com/xivdev/Penumbra/blob/master/Penumbra/Import/Models/Export/MeshExporter.cs
|
||||||
|
let affected_shape_mesh: Vec<&ShapeMesh> = model.shape_meshes.iter()
|
||||||
|
.skip(shape.shape_mesh_start_index[i as usize] as usize)
|
||||||
|
.take(shape.shape_mesh_count[i as usize] as usize)
|
||||||
|
.filter(|shape_mesh| shape_mesh.mesh_index_offset == model.meshes[j as usize].start_index).collect();
|
||||||
|
|
||||||
|
let shape_values: Vec<&ShapeValue> = affected_shape_mesh.iter()
|
||||||
|
.flat_map(|shape_mesh| model.shape_values.iter().skip(shape_mesh.shape_value_offset as usize).take(shape_mesh.shape_value_count as usize))
|
||||||
|
.filter(|shape_value| shape_value.base_indices_index >= model.meshes[j as usize].start_index as u16 && shape_value.base_indices_index < (model.meshes[j as usize].start_index + model.meshes[j as usize].index_count) as u16)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut morphed_vertices = vec![Vertex::default(); vertices.len()];
|
||||||
|
|
||||||
|
if !shape_values.is_empty() {
|
||||||
|
for shape_value in shape_values {
|
||||||
|
let old_vertex = vertices[indices[shape_value.base_indices_index as usize] as usize];
|
||||||
|
let new_vertex = vertices[shape_value.replacing_vertex_index as usize - model.meshes[j as usize].start_index as usize];
|
||||||
|
let mut vertex = &mut morphed_vertices[indices[shape_value.base_indices_index as usize] as usize];
|
||||||
|
|
||||||
|
vertex.position[0] = new_vertex.position[0] - old_vertex.position[0];
|
||||||
|
vertex.position[1] = new_vertex.position[1] - old_vertex.position[1];
|
||||||
|
vertex.position[2] = new_vertex.position[2] - old_vertex.position[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut offset = shape.string_offset;
|
||||||
|
let mut string = String::new();
|
||||||
|
|
||||||
|
let mut next_char = model.header.strings[offset as usize] as char;
|
||||||
|
while next_char != '\0' {
|
||||||
|
string.push(next_char);
|
||||||
|
offset += 1;
|
||||||
|
next_char = model.header.strings[offset as usize] as char;
|
||||||
|
}
|
||||||
|
|
||||||
|
shapes.push(Shape {
|
||||||
|
name: string,
|
||||||
|
morphed_vertices
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.push(Part { mesh_index: j, vertices, indices, material_index, submeshes, shapes });
|
||||||
}
|
}
|
||||||
|
|
||||||
lods.push(Lod { parts });
|
lods.push(Lod { parts });
|
||||||
|
|
Loading…
Add table
Reference in a new issue