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:
parent
5f1721fe14
commit
5cce23bd3c
1 changed files with 97 additions and 19 deletions
116
src/model.rs
116
src/model.rs
|
@ -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()?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue