1
Fork 0
mirror of https://github.com/redstrate/Physis.git synced 2025-04-26 14:17:45 +00:00

Finish model writing support

It now handles writing a model of a higher vertex count (which is
unfortunately really common in round trips, for example in Blender.)

Some of the code is still WIP, but it works!
This commit is contained in:
Joshua Goins 2023-12-12 21:43:04 -05:00
parent 5f1721fe14
commit 5cce23bd3c

View file

@ -175,8 +175,8 @@ struct Mesh {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
struct Submesh { struct Submesh {
index_offset: i32, index_offset: u32,
index_count: i32, index_count: u32,
attribute_index_mask: u32, attribute_index_mask: u32,
@ -320,11 +320,20 @@ pub struct Vertex {
pub bone_id: [u8; 4], pub bone_id: [u8; 4],
} }
#[derive(Clone, Copy)]
#[repr(C)]
pub struct SubMesh {
submesh_index: usize,
pub index_count: u32,
pub index_offset: u32
}
pub struct Part { pub struct Part {
mesh_index: u16, mesh_index: u16,
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 struct Lod { pub struct Lod {
@ -340,7 +349,6 @@ pub struct MDL {
file_header: ModelFileHeader, file_header: ModelFileHeader,
vertex_declarations: Vec<VertexDeclaration>, vertex_declarations: Vec<VertexDeclaration>,
model_data: ModelData, model_data: ModelData,
header_offset: u64,
pub lods: Vec<Lod>, pub lods: Vec<Lod>,
pub affected_bone_names: Vec<String>, pub affected_bone_names: Vec<String>,
@ -442,7 +450,7 @@ impl MDL {
+ model.meshes[j as usize].vertex_buffer_offsets + model.meshes[j as usize].vertex_buffer_offsets
[element.stream as usize] [element.stream as usize]
+ element.offset as u32 + element.offset as u32
+ model.meshes[j as usize].vertex_buffer_strides // TODO: is j really correct? this might fix the broken LoDs + model.meshes[j as usize].vertex_buffer_strides
[element.stream as usize] [element.stream as usize]
as u32 as u32
* k as u32) as u64, * k as u32) as u64,
@ -564,7 +572,16 @@ impl MDL {
indices.push(cursor.read_le::<u16>().ok()?); indices.push(cursor.read_le::<u16>().ok()?);
} }
parts.push(Part { mesh_index: j, vertices, indices, material_index }); let mut submeshes: Vec<SubMesh> = Vec::with_capacity(model.meshes[j as usize].submesh_count as usize);
for i in 0..model.meshes[j as usize].submesh_count {
submeshes.push(SubMesh {
submesh_index: model.meshes[j as usize].submesh_index as usize + i as usize,
index_count: model.submeshes[model.meshes[j as usize].submesh_index as usize + i as usize].index_count,
index_offset: model.submeshes[model.meshes[j as usize].submesh_index as usize + i as usize].index_offset,
});
}
parts.push(Part { mesh_index: j, vertices, indices, material_index, submeshes });
} }
lods.push(Lod { parts }); lods.push(Lod { parts });
@ -574,32 +591,42 @@ impl MDL {
file_header: model_file_header, file_header: model_file_header,
vertex_declarations, vertex_declarations,
model_data: model, model_data: model,
header_offset,
lods, lods,
affected_bone_names, affected_bone_names,
material_names material_names
}) })
} }
pub fn replace_vertices(&mut self, lod_index: usize, part_index: usize, vertices: &[Vertex], indices: &[u16]) { pub fn replace_vertices(&mut self, lod_index: usize, part_index: usize, vertices: &[Vertex], indices: &[u16], submeshes: &[SubMesh]) {
let part = &mut self.lods[lod_index].parts[part_index]; let part = &mut self.lods[lod_index].parts[part_index];
part.vertices = Vec::from(vertices); part.vertices = Vec::from(vertices);
part.indices = Vec::from(indices); part.indices = Vec::from(indices);
for (i, submesh) in part.submeshes.iter().enumerate() {
if i < submeshes.len() {
self.model_data.submeshes[submesh.submesh_index].index_offset = submeshes[i].index_offset;
self.model_data.submeshes[submesh.submesh_index].index_count = submeshes[i].index_count;
}
}
// Update vertex count in header // Update vertex count in header
self.model_data.meshes[part.mesh_index as usize].vertex_count = part.vertices.len() as u16; self.model_data.meshes[part.mesh_index as usize].vertex_count = part.vertices.len() as u16;
self.model_data.meshes[part.mesh_index as usize].index_count = part.indices.len() as u16 as u32; self.model_data.meshes[part.mesh_index as usize].index_count = part.indices.len() as u32;
// update values // update values
for i in 0..self.file_header.lod_count { for i in 0..self.file_header.lod_count {
let mut vertex_offset = 0; let mut vertex_offset = 0;
let mut index_count = 0;
for j in self.model_data.lods[i as usize].mesh_index for j in self.model_data.lods[i as usize].mesh_index
..self.model_data.lods[i as usize].mesh_index + self.model_data.lods[i as usize].mesh_count ..self.model_data.lods[i as usize].mesh_index + self.model_data.lods[i as usize].mesh_count
{ {
let mesh = &mut self.model_data.meshes[j as usize]; let mesh = &mut self.model_data.meshes[j as usize];
mesh.start_index = index_count;
index_count += mesh.index_count;
for i in 0..mesh.vertex_stream_count as usize { for i in 0..mesh.vertex_stream_count as usize {
mesh.vertex_buffer_offsets[i] = vertex_offset; mesh.vertex_buffer_offsets[i] = vertex_offset;
vertex_offset += mesh.vertex_count as u32 * mesh.vertex_buffer_strides[i] as u32; vertex_offset += mesh.vertex_count as u32 * mesh.vertex_buffer_strides[i] as u32;
@ -609,12 +636,14 @@ impl MDL {
for lod in &mut self.model_data.lods { for lod in &mut self.model_data.lods {
let mut total_vertex_buffer_size = 0; let mut total_vertex_buffer_size = 0;
let mut total_index_buffer_size = 0;
// still slightly off? // still slightly off?
for j in lod.mesh_index for j in lod.mesh_index
..lod.mesh_index + lod.mesh_count ..lod.mesh_index + lod.mesh_count
{ {
let vertex_count = self.model_data.meshes[j as usize].vertex_count; let vertex_count = self.model_data.meshes[j as usize].vertex_count;
let index_count = self.model_data.meshes[j as usize].index_count;
let mut total_vertex_stride: u32 = 0; let mut total_vertex_stride: u32 = 0;
for i in 0..self.model_data.meshes[j as usize].vertex_stream_count as usize { for i in 0..self.model_data.meshes[j as usize].vertex_stream_count as usize {
@ -622,22 +651,63 @@ impl MDL {
} }
total_vertex_buffer_size += vertex_count as u32 * total_vertex_stride; total_vertex_buffer_size += vertex_count as u32 * total_vertex_stride;
total_index_buffer_size += index_count * 2; // sizeof uint16, TODO: don't hardcode
} }
lod.vertex_buffer_size = total_vertex_buffer_size; // sizeof Vertex // Unknown padding?
let mut index_padding = 16 - total_index_buffer_size % 16;
if index_padding == 16 {
index_padding = 0;
}
lod.vertex_buffer_size = total_vertex_buffer_size;
lod.index_buffer_size = total_index_buffer_size + index_padding;
} }
// update lod values // update lod values
let mut data_offset = self.header_offset as u32; // TODO: From Xande, need to be cleaned up :)
self.file_header.stack_size = self.file_header.vertex_declaration_count as u32 * 136;
self.file_header.runtime_size =
2 //StringCount
+ 2 // Unknown
+ 4 //StringSize
+ self.model_data.header.string_size
+ 56 //ModelHeader
+ ( self.model_data.element_ids.len() as u32 * 32 )
+ ( 3 * 60 ) // 3 Lods
//+ ( /*file.ModelHeader.ExtraLodEnabled ? 40*/ 0 )
+ self.model_data.meshes.len() as u32 * 36
+ self.model_data.attribute_name_offsets.len() as u32 * 4
+ self.model_data.header.terrain_shadow_mesh_count as u32 * 20
+ self.model_data.header.submesh_count as u32 * 16
+ self.model_data.header.terrain_shadow_submesh_count as u32 * 10
+ self.model_data.material_name_offsets.len() as u32 * 4
+ self.model_data.bone_name_offsets.len() as u32 * 4
+ self.model_data.bone_tables.len() as u32 * 132
+ self.model_data.header.shape_count as u32 * 16
+ self.model_data.header.shape_mesh_count as u32 * 12
+ self.model_data.header.shape_value_count as u32 * 4
+ 4 // SubmeshBoneMapSize
+ self.model_data.submesh_bone_map.len() as u32 * 2
+ 8 // PaddingAmount and Padding
+ ( 4 * 32 ) // 4 BoundingBoxes
+ ( self.model_data.header.bone_count as u32 * 32 );
let mut vertex_offset = self.file_header.runtime_size
+ 68 // model file header
+ self.file_header.stack_size;
for lod in &mut self.model_data.lods { for lod in &mut self.model_data.lods {
lod.vertex_data_offset = data_offset; lod.vertex_data_offset = vertex_offset;
data_offset = lod.vertex_data_offset + lod.vertex_buffer_size; vertex_offset = lod.vertex_data_offset + lod.vertex_buffer_size;
lod.index_data_offset = data_offset; lod.index_data_offset = vertex_offset;
data_offset = lod.index_data_offset + lod.index_buffer_size; // dummy
lod.edge_geometry_data_offset = vertex_offset;
vertex_offset = lod.index_data_offset + lod.index_buffer_size;
} }
for i in 0..self.lods.len() { for i in 0..self.lods.len() {
@ -647,6 +717,14 @@ impl MDL {
for i in 0..self.lods.len() { for i in 0..self.lods.len() {
self.file_header.vertex_offsets[i] = self.model_data.lods[i].vertex_data_offset; self.file_header.vertex_offsets[i] = self.model_data.lods[i].vertex_data_offset;
} }
for i in 0..self.lods.len() {
self.file_header.index_buffer_size[i] = self.model_data.lods[i].index_buffer_size;
}
for i in 0..self.lods.len() {
self.file_header.index_offsets[i] = self.model_data.lods[i].index_data_offset;
}
} }
pub fn write_to_buffer(&self) -> Option<ByteBuffer> { pub fn write_to_buffer(&self) -> Option<ByteBuffer> {
@ -683,12 +761,12 @@ impl MDL {
.seek(SeekFrom::Start( .seek(SeekFrom::Start(
(self.model_data.lods[l].vertex_data_offset (self.model_data.lods[l].vertex_data_offset
+ self.model_data.meshes[part.mesh_index as usize].vertex_buffer_offsets + self.model_data.meshes[part.mesh_index as usize].vertex_buffer_offsets
[element.stream as usize] [element.stream as usize]
+ element.offset as u32 + element.offset as u32
+ self.model_data.meshes[part.mesh_index as usize].vertex_buffer_strides + self.model_data.meshes[part.mesh_index as usize].vertex_buffer_strides
[element.stream as usize] [element.stream as usize]
as u32 as u32
* k as u32) as u64, * k as u32) as u64,
)) ))
.ok()?; .ok()?;