physis/
model.rs

1// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#![allow(clippy::unnecessary_fallible_conversions)] // This wrongly trips on binrw code
5
6use std::io::{Cursor, Seek, SeekFrom};
7use std::mem::size_of;
8
9use binrw::BinRead;
10use binrw::BinReaderExt;
11use binrw::{BinWrite, BinWriterExt, binrw};
12
13use crate::common_file_operations::{read_bool_from, write_bool_as};
14use crate::model_vertex_declarations::{
15    VERTEX_ELEMENT_SIZE, VertexDeclaration, VertexType, VertexUsage, vertex_element_parser,
16    vertex_element_writer,
17};
18use crate::{ByteBuffer, ByteSpan};
19
20pub const NUM_VERTICES: u32 = 17;
21
22#[binrw]
23#[derive(Debug, Clone, PartialEq)]
24#[brw(little)]
25pub struct ModelFileHeader {
26    pub version: u32,
27
28    pub stack_size: u32,
29    pub runtime_size: u32,
30
31    pub vertex_declaration_count: u16,
32    pub material_count: u16,
33
34    pub vertex_offsets: [u32; 3],
35    pub index_offsets: [u32; 3],
36    pub vertex_buffer_size: [u32; 3],
37    pub index_buffer_size: [u32; 3],
38
39    pub lod_count: u8,
40
41    #[br(map = read_bool_from::<u8>)]
42    #[bw(map = write_bool_as::<u8>)]
43    pub index_buffer_streaming_enabled: bool,
44    #[br(map = read_bool_from::<u8>)]
45    #[bw(map = write_bool_as::<u8>)]
46    #[brw(pad_after = 1)]
47    pub has_edge_geometry: bool,
48}
49
50#[binrw]
51#[brw(repr = u8)]
52#[derive(Debug, Clone, PartialEq)]
53enum ModelFlags1 {
54    DustOcclusionEnabled = 0x80,
55    SnowOcclusionEnabled = 0x40,
56    RainOcclusionEnabled = 0x20,
57    Unknown1 = 0x10,
58    LightingReflectionEnabled = 0x08,
59    WavingAnimationDisabled = 0x04,
60    LightShadowDisabled = 0x02,
61    ShadowDisabled = 0x01,
62}
63
64#[binrw]
65#[brw(repr = u8)]
66#[derive(Debug, Clone, PartialEq)]
67enum ModelFlags2 {
68    None = 0x0,
69    Unknown2 = 0x80,
70    BgUvScrollEnabled = 0x40,
71    EnableForceNonResident = 0x20,
72    ExtraLodEnabled = 0x10,
73    ShadowMaskEnabled = 0x08,
74    ForceLodRangeEnabled = 0x04,
75    EdgeGeometryEnabled = 0x02,
76    Unknown3 = 0x01,
77}
78
79#[binrw]
80#[derive(Debug, Clone, PartialEq)]
81#[br(import { vertex_declaration_count: u16 })]
82#[allow(dead_code)]
83pub struct ModelHeader {
84    #[br(args(vertex_declaration_count), parse_with = vertex_element_parser)]
85    #[bw(write_with = vertex_element_writer)]
86    pub vertex_declarations: Vec<VertexDeclaration>,
87
88    #[brw(pad_after = 2)]
89    string_count: u16,
90    string_size: u32,
91
92    #[br(count = string_size)]
93    strings: Vec<u8>,
94
95    radius: f32,
96
97    mesh_count: u16,
98    attribute_count: u16,
99    submesh_count: u16,
100    material_count: u16,
101    bone_count: u16,
102    bone_table_count: u16,
103    shape_count: u16,
104    shape_mesh_count: u16,
105    shape_value_count: u16,
106
107    lod_count: u8,
108
109    flags1: ModelFlags1,
110
111    element_id_count: u16,
112    terrain_shadow_mesh_count: u8,
113
114    flags2: ModelFlags2,
115
116    model_clip_out_of_distance: f32,
117    shadow_clip_out_of_distance: f32,
118
119    unknown4: u16,
120
121    terrain_shadow_submesh_count: u16,
122
123    unknown5: u8,
124
125    bg_change_material_index: u8,
126    bg_crest_change_material_index: u8,
127
128    unknown6: u8,
129    unknown7: u16,
130    unknown8: u16,
131    #[brw(pad_after = 6)]
132    unknown9: u16,
133}
134
135#[binrw]
136#[derive(Debug, Clone, PartialEq)]
137#[allow(dead_code)]
138struct MeshLod {
139    mesh_index: u16,
140    mesh_count: u16,
141
142    model_lod_range: f32,
143    texture_lod_range: f32,
144
145    water_mesh_index: u16,
146    water_mesh_count: u16,
147
148    shadow_mesh_index: u16,
149    shadow_mesh_count: u16,
150
151    terrain_shadow_mesh_count: u16,
152    terrain_shadow_mesh_index: u16,
153
154    vertical_fog_mesh_index: u16,
155    vertical_fog_mesh_count: u16,
156
157    // unused on win32 according to lumina devs
158    edge_geometry_size: u32,
159    edge_geometry_data_offset: u32,
160
161    #[brw(pad_after = 4)]
162    polygon_count: u32,
163
164    vertex_buffer_size: u32,
165    index_buffer_size: u32,
166    vertex_data_offset: u32,
167    index_data_offset: u32,
168}
169
170#[binrw]
171#[derive(Debug, Clone, PartialEq)]
172#[allow(dead_code)]
173struct Mesh {
174    #[brw(pad_after = 2)]
175    vertex_count: u16,
176    index_count: u32,
177
178    material_index: u16,
179    submesh_index: u16,
180    submesh_count: u16,
181
182    bone_table_index: u16,
183    start_index: u32,
184
185    vertex_buffer_offsets: [u32; 3],
186    vertex_buffer_strides: [u8; 3],
187
188    vertex_stream_count: u8,
189}
190
191#[binrw]
192#[derive(Debug, Clone, PartialEq)]
193#[allow(dead_code)]
194struct Submesh {
195    index_offset: u32,
196    index_count: u32,
197
198    attribute_index_mask: u32,
199
200    bone_start_index: u16,
201    bone_count: u16,
202}
203
204#[binrw]
205#[derive(Debug, Clone, PartialEq)]
206#[allow(dead_code)]
207struct BoneTable {
208    bone_indices: [u16; 64],
209
210    #[brw(pad_after = 3)]
211    bone_count: u8,
212}
213
214#[binrw]
215#[derive(Debug, Clone, PartialEq)]
216#[allow(dead_code)]
217struct BoneTableV2 {
218    #[br(pad_before = 2)]
219    bone_count: u16,
220
221    #[br(count = bone_count)]
222    bone_indices: Vec<u16>,
223
224    // align to 4 bytes
225    // TODO: use br align_to?
226    #[br(if(bone_count % 2 == 0))]
227    padding: u16,
228}
229
230#[binrw]
231#[derive(Debug, Clone, PartialEq)]
232#[allow(dead_code)]
233struct BoundingBox {
234    min: [f32; 4],
235    max: [f32; 4],
236}
237
238#[binrw]
239#[derive(Debug, Clone, PartialEq)]
240#[allow(dead_code)]
241struct TerrainShadowMesh {
242    index_count: u32,
243    start_index: u32,
244    vertex_buffer_offset: u32,
245    vertex_count: u16,
246    submesh_index: u16,
247    submesh_count: u16,
248    vertex_buffer_stride: u8,
249    padding: u8,
250}
251
252#[binrw]
253#[derive(Debug, Clone, PartialEq)]
254#[allow(dead_code)]
255struct TerrainShadowSubmesh {
256    index_offset: u32,
257    index_count: u32,
258    unknown1: u16,
259    unknown2: u16,
260}
261
262#[binrw]
263#[derive(Debug, Clone, PartialEq)]
264#[allow(dead_code)]
265struct ShapeStruct {
266    string_offset: u32,
267    shape_mesh_start_index: [u16; 3],
268    shape_mesh_count: [u16; 3],
269}
270
271#[binrw]
272#[derive(Debug, Clone, PartialEq)]
273#[allow(dead_code)]
274struct ShapeMesh {
275    mesh_index_offset: u32,
276    shape_value_count: u32,
277    shape_value_offset: u32,
278}
279
280#[binrw]
281#[derive(Debug, Clone, PartialEq)]
282#[allow(dead_code)]
283struct ShapeValue {
284    base_indices_index: u16,
285    replacing_vertex_index: u16,
286}
287
288#[binrw]
289#[derive(Debug, Clone, PartialEq)]
290#[allow(dead_code)]
291#[br(import {file_header: &ModelFileHeader})]
292#[brw(little)]
293pub struct ModelData {
294    #[br(args { vertex_declaration_count: file_header.vertex_declaration_count })]
295    pub header: ModelHeader,
296
297    #[br(count = header.element_id_count)]
298    element_ids: Vec<ElementId>,
299
300    #[br(count = 3)]
301    lods: Vec<MeshLod>,
302
303    #[br(count = header.mesh_count)]
304    meshes: Vec<Mesh>,
305
306    #[br(count = header.attribute_count)]
307    attribute_name_offsets: Vec<u32>,
308
309    #[br(count = header.terrain_shadow_mesh_count)]
310    terrain_shadow_meshes: Vec<TerrainShadowMesh>,
311
312    #[br(count = header.submesh_count)]
313    submeshes: Vec<Submesh>,
314
315    #[br(count = header.terrain_shadow_submesh_count)]
316    terrain_shadow_submeshes: Vec<TerrainShadowSubmesh>,
317
318    #[br(count = header.material_count)]
319    material_name_offsets: Vec<u32>,
320
321    #[br(count = header.bone_count)]
322    bone_name_offsets: Vec<u32>,
323
324    #[br(count = header.bone_table_count)]
325    #[br(if(file_header.version <= 0x1000005))]
326    bone_tables: Vec<BoneTable>,
327
328    #[br(count = header.bone_table_count)]
329    #[br(if(file_header.version >= 0x1000006))]
330    bone_tables_v2: Vec<BoneTableV2>,
331
332    #[br(count = header.shape_count)]
333    shapes: Vec<ShapeStruct>,
334
335    #[br(count = header.shape_mesh_count)]
336    shape_meshes: Vec<ShapeMesh>,
337
338    #[br(count = header.shape_value_count)]
339    shape_values: Vec<ShapeValue>,
340
341    // TODO: try to unify these fields?
342    #[br(if(file_header.version <= 0x1000005))]
343    submesh_bone_map_size: u32,
344
345    // hehe, Dawntrail made this u16 instead of u32. fun?
346    #[br(if(file_header.version >= 0x1000006))]
347    submesh_bone_map_size_v2: u16,
348
349    #[br(count = if file_header.version >= 0x1000006 { (submesh_bone_map_size_v2 / 2) as u32 } else { submesh_bone_map_size / 2 } )]
350    submesh_bone_map: Vec<u16>,
351
352    padding_amount: u8,
353    #[br(count = padding_amount)]
354    unknown_padding: Vec<u8>,
355
356    // TODO: these are still wrong on Dawntrail!
357    bounding_box: BoundingBox,
358    model_bounding_box: BoundingBox,
359    water_bounding_box: BoundingBox,
360    vertical_fog_bounding_box: BoundingBox,
361
362    #[br(count = header.bone_count)]
363    bone_bounding_boxes: Vec<BoundingBox>,
364}
365
366#[binrw]
367#[derive(Debug, Clone, PartialEq)]
368#[allow(dead_code)]
369struct ElementId {
370    element_id: u32,
371    parent_bone_name: u32,
372    translate: [f32; 3],
373    rotate: [f32; 3],
374}
375
376#[derive(Clone, Copy, PartialEq, Debug)]
377#[repr(C)]
378pub struct Vertex {
379    pub position: [f32; 3],
380    pub uv0: [f32; 2],
381    pub uv1: [f32; 2],
382    pub normal: [f32; 3],
383    pub bitangent: [f32; 4],
384    //pub bitangent1: [f32; 4], // TODO: need to figure out what the heck this could be
385    pub color: [f32; 4],
386
387    pub bone_weight: [f32; 4],
388    pub bone_id: [u8; 4],
389}
390
391impl Default for Vertex {
392    fn default() -> Self {
393        Self {
394            position: [0.0; 3],
395            uv0: [0.0; 2],
396            uv1: [0.0; 2],
397            normal: [0.0; 3],
398            bitangent: [0.0; 4],
399            color: [0.0; 4],
400            bone_weight: [0.0; 4],
401            bone_id: [0u8; 4],
402        }
403    }
404}
405
406#[derive(Debug, Clone, Copy)]
407#[repr(C)]
408pub struct NewShapeValue {
409    pub base_index: u32,
410    pub replacing_vertex: Vertex,
411}
412
413#[derive(Debug, Clone, Copy)]
414#[repr(C)]
415pub struct SubMesh {
416    submesh_index: usize,
417    pub index_count: u32,
418    pub index_offset: u32,
419}
420
421#[derive(Debug, Clone)]
422pub struct Shape {
423    pub name: String,
424    pub morphed_vertices: Vec<Vertex>,
425}
426
427/// Corresponds to a "Mesh" in an LOD
428#[derive(Debug, Clone)]
429pub struct Part {
430    mesh_index: u16,
431    pub vertices: Vec<Vertex>,
432    /// Indexed by VertexElement::stream
433    pub vertex_streams: Vec<Vec<u8>>,
434    pub vertex_stream_strides: Vec<usize>,
435    pub indices: Vec<u16>,
436    pub material_index: u16,
437    pub submeshes: Vec<SubMesh>,
438    pub shapes: Vec<Shape>,
439}
440
441#[derive(Debug, Clone)]
442pub struct Lod {
443    pub parts: Vec<Part>,
444}
445
446#[derive(Debug, Clone)]
447pub struct MDL {
448    file_header: ModelFileHeader,
449    pub model_data: ModelData,
450
451    pub lods: Vec<Lod>,
452    pub affected_bone_names: Vec<String>,
453    pub material_names: Vec<String>,
454}
455
456impl MDL {
457    pub fn from_existing(buffer: ByteSpan) -> Option<MDL> {
458        let mut cursor = Cursor::new(buffer);
459        let model_file_header = ModelFileHeader::read(&mut cursor).ok()?;
460
461        let model = ModelData::read_args(
462            &mut cursor,
463            binrw::args! { file_header: &model_file_header },
464        )
465        .ok()?;
466
467        let mut affected_bone_names = vec![];
468
469        for offset in &model.bone_name_offsets {
470            let mut offset = *offset;
471            let mut string = String::new();
472
473            let mut next_char = model.header.strings[offset as usize] as char;
474            while next_char != '\0' {
475                string.push(next_char);
476                offset += 1;
477                next_char = model.header.strings[offset as usize] as char;
478            }
479
480            affected_bone_names.push(string);
481        }
482
483        let mut material_names = vec![];
484
485        for offset in &model.material_name_offsets {
486            let mut offset = *offset;
487            let mut string = String::new();
488
489            let mut next_char = model.header.strings[offset as usize] as char;
490            while next_char != '\0' {
491                string.push(next_char);
492                offset += 1;
493                next_char = model.header.strings[offset as usize] as char;
494            }
495
496            material_names.push(string);
497        }
498
499        let mut lods = vec![];
500
501        for i in 0..model.header.lod_count {
502            let mut parts = vec![];
503
504            for j in model.lods[i as usize].mesh_index
505                ..model.lods[i as usize].mesh_index + model.lods[i as usize].mesh_count
506            {
507                let declaration = &model.header.vertex_declarations[j as usize];
508                let vertex_count = model.meshes[j as usize].vertex_count;
509                let material_index = model.meshes[j as usize].material_index;
510
511                let mut vertices: Vec<Vertex> = vec![Vertex::default(); vertex_count as usize];
512
513                for k in 0..vertex_count {
514                    for element in &declaration.elements {
515                        cursor
516                            .seek(SeekFrom::Start(
517                                (model.lods[i as usize].vertex_data_offset
518                                    + model.meshes[j as usize].vertex_buffer_offsets
519                                        [element.stream as usize]
520                                    + element.offset as u32
521                                    + model.meshes[j as usize].vertex_buffer_strides
522                                        [element.stream as usize]
523                                        as u32
524                                        * k as u32) as u64,
525                            ))
526                            .ok()?;
527
528                        match element.vertex_usage {
529                            VertexUsage::Position => match element.vertex_type {
530                                VertexType::Single4 => {
531                                    vertices[k as usize].position.clone_from_slice(
532                                        &MDL::read_single4(&mut cursor).unwrap()[0..3],
533                                    );
534                                }
535                                VertexType::Half4 => {
536                                    vertices[k as usize].position.clone_from_slice(
537                                        &MDL::read_half4(&mut cursor).unwrap()[0..3],
538                                    );
539                                }
540                                VertexType::Single3 => {
541                                    vertices[k as usize].position =
542                                        MDL::read_single3(&mut cursor).unwrap();
543                                }
544                                _ => {
545                                    panic!(
546                                        "Unexpected vertex type for position: {:#?}",
547                                        element.vertex_type
548                                    );
549                                }
550                            },
551                            VertexUsage::BlendWeights => match element.vertex_type {
552                                VertexType::ByteFloat4 => {
553                                    vertices[k as usize].bone_weight =
554                                        MDL::read_byte_float4(&mut cursor).unwrap();
555                                }
556                                VertexType::Byte4 => {
557                                    vertices[k as usize].bone_weight =
558                                        MDL::read_tangent(&mut cursor).unwrap();
559                                }
560                                VertexType::UnsignedShort4 => {
561                                    let bytes = MDL::read_unsigned_short4(&mut cursor).unwrap();
562                                    vertices[k as usize].bone_weight = [
563                                        f32::from(bytes[0]),
564                                        f32::from(bytes[1]),
565                                        f32::from(bytes[2]),
566                                        f32::from(bytes[3]),
567                                    ];
568                                }
569                                _ => {
570                                    panic!(
571                                        "Unexpected vertex type for blendweight: {:#?}",
572                                        element.vertex_type
573                                    );
574                                }
575                            },
576                            VertexUsage::BlendIndices => match element.vertex_type {
577                                VertexType::Byte4 => {
578                                    vertices[k as usize].bone_id =
579                                        MDL::read_byte4(&mut cursor).unwrap();
580                                }
581                                VertexType::UnsignedShort4 => {
582                                    let shorts = MDL::read_unsigned_short4(&mut cursor).unwrap();
583                                    vertices[k as usize].bone_id = [
584                                        shorts[0] as u8,
585                                        shorts[1] as u8,
586                                        shorts[2] as u8,
587                                        shorts[3] as u8,
588                                    ];
589                                }
590                                _ => {
591                                    panic!(
592                                        "Unexpected vertex type for blendindice: {:#?}",
593                                        element.vertex_type
594                                    );
595                                }
596                            },
597                            VertexUsage::Normal => match element.vertex_type {
598                                VertexType::Half4 => {
599                                    vertices[k as usize].normal.clone_from_slice(
600                                        &MDL::read_half4(&mut cursor).unwrap()[0..3],
601                                    );
602                                }
603                                VertexType::Single3 => {
604                                    vertices[k as usize].normal =
605                                        MDL::read_single3(&mut cursor).unwrap();
606                                }
607                                _ => {
608                                    panic!(
609                                        "Unexpected vertex type for normal: {:#?}",
610                                        element.vertex_type
611                                    );
612                                }
613                            },
614                            VertexUsage::UV => match element.vertex_type {
615                                VertexType::ByteFloat4 => {
616                                    let combined = MDL::read_byte_float4(&mut cursor).unwrap();
617
618                                    vertices[k as usize].uv0.clone_from_slice(&combined[0..2]);
619                                    vertices[k as usize].uv1.clone_from_slice(&combined[2..4]);
620                                }
621                                VertexType::Half4 => {
622                                    let combined = MDL::read_half4(&mut cursor).unwrap();
623
624                                    vertices[k as usize].uv0.clone_from_slice(&combined[0..2]);
625                                    vertices[k as usize].uv1.clone_from_slice(&combined[2..4]);
626                                }
627                                VertexType::Single4 => {
628                                    let combined = MDL::read_single4(&mut cursor).unwrap();
629
630                                    vertices[k as usize].uv0.clone_from_slice(&combined[0..2]);
631                                    vertices[k as usize].uv1.clone_from_slice(&combined[2..4]);
632                                }
633                                VertexType::Half2 => {
634                                    let combined = MDL::read_half2(&mut cursor).unwrap();
635
636                                    vertices[k as usize].uv0.clone_from_slice(&combined[0..2]);
637                                }
638                                _ => {
639                                    panic!(
640                                        "Unexpected vertex type for uv: {:#?}",
641                                        element.vertex_type
642                                    );
643                                }
644                            },
645                            VertexUsage::BiTangent => match element.vertex_type {
646                                VertexType::ByteFloat4 => {
647                                    vertices[k as usize].bitangent =
648                                        MDL::read_tangent(&mut cursor).unwrap();
649                                }
650                                _ => {
651                                    panic!(
652                                        "Unexpected vertex type for bitangent: {:#?}",
653                                        element.vertex_type
654                                    );
655                                }
656                            },
657                            VertexUsage::Tangent => {
658                                match element.vertex_type {
659                                    // Used for... terrain..?
660                                    VertexType::ByteFloat4 => {}
661                                    _ => {
662                                        panic!(
663                                            "Unexpected vertex type for tangent: {:#?}",
664                                            element.vertex_type
665                                        );
666                                    }
667                                }
668                            }
669                            VertexUsage::Color => match element.vertex_type {
670                                VertexType::ByteFloat4 => {
671                                    vertices[k as usize].color =
672                                        MDL::read_byte_float4(&mut cursor).unwrap();
673                                }
674                                _ => {
675                                    panic!(
676                                        "Unexpected vertex type for color: {:#?}",
677                                        element.vertex_type
678                                    );
679                                }
680                            },
681                        }
682                    }
683                }
684
685                cursor
686                    .seek(SeekFrom::Start(
687                        (model_file_header.index_offsets[i as usize]
688                            + (model.meshes[j as usize].start_index * size_of::<u16>() as u32))
689                            as u64,
690                    ))
691                    .ok()?;
692
693                // TODO: optimize!
694                let mut indices: Vec<u16> =
695                    Vec::with_capacity(model.meshes[j as usize].index_count as usize);
696                for _ in 0..model.meshes[j as usize].index_count {
697                    indices.push(cursor.read_le::<u16>().ok()?);
698                }
699
700                let mut submeshes: Vec<SubMesh> =
701                    Vec::with_capacity(model.meshes[j as usize].submesh_count as usize);
702                for i in 0..model.meshes[j as usize].submesh_count {
703                    submeshes.push(SubMesh {
704                        submesh_index: model.meshes[j as usize].submesh_index as usize + i as usize,
705                        index_count: model.submeshes
706                            [model.meshes[j as usize].submesh_index as usize + i as usize]
707                            .index_count,
708                        index_offset: model.submeshes
709                            [model.meshes[j as usize].submesh_index as usize + i as usize]
710                            .index_offset,
711                    });
712                }
713
714                let mut shapes = vec![];
715
716                for shape in &model.shapes {
717                    // Adapted from https://github.com/xivdev/Penumbra/blob/master/Penumbra/Import/Models/Export/MeshExporter.cs
718                    let affected_shape_mesh: Vec<&ShapeMesh> = model
719                        .shape_meshes
720                        .iter()
721                        .skip(shape.shape_mesh_start_index[i as usize] as usize)
722                        .take(shape.shape_mesh_count[i as usize] as usize)
723                        .filter(|shape_mesh| {
724                            shape_mesh.mesh_index_offset == model.meshes[j as usize].start_index
725                        })
726                        .collect();
727
728                    let shape_values: Vec<&ShapeValue> = affected_shape_mesh
729                        .iter()
730                        .flat_map(|shape_mesh| {
731                            model
732                                .shape_values
733                                .iter()
734                                .skip(shape_mesh.shape_value_offset as usize)
735                                .take(shape_mesh.shape_value_count as usize)
736                        })
737                        .filter(|shape_value| {
738                            shape_value.base_indices_index
739                                >= model.meshes[j as usize].start_index as u16
740                                && shape_value.base_indices_index
741                                    < (model.meshes[j as usize].start_index
742                                        + model.meshes[j as usize].index_count)
743                                        as u16
744                        })
745                        .collect();
746
747                    let mut morphed_vertices = vec![Vertex::default(); vertices.len()];
748
749                    if !shape_values.is_empty() {
750                        for shape_value in shape_values {
751                            let old_vertex =
752                                vertices[indices[shape_value.base_indices_index as usize] as usize];
753                            let new_vertex = vertices[shape_value.replacing_vertex_index as usize];
754                            let vertex = &mut morphed_vertices
755                                [indices[shape_value.base_indices_index as usize] as usize];
756
757                            vertex.position[0] = new_vertex.position[0] - old_vertex.position[0];
758                            vertex.position[1] = new_vertex.position[1] - old_vertex.position[1];
759                            vertex.position[2] = new_vertex.position[2] - old_vertex.position[2];
760                        }
761
762                        let mut offset = shape.string_offset;
763                        let mut string = String::new();
764
765                        let mut next_char = model.header.strings[offset as usize] as char;
766                        while next_char != '\0' {
767                            string.push(next_char);
768                            offset += 1;
769                            next_char = model.header.strings[offset as usize] as char;
770                        }
771
772                        shapes.push(Shape {
773                            name: string,
774                            morphed_vertices,
775                        });
776                    }
777                }
778
779                let mut vertex_streams = vec![];
780                let mut vertex_stream_strides = vec![];
781                let mesh = &model.meshes[j as usize];
782                for stream in 0..mesh.vertex_stream_count {
783                    let mut vertex_data = vec![];
784                    let stride = mesh.vertex_buffer_strides[stream as usize];
785                    for z in 0..mesh.vertex_count {
786                        // TODO: read the entire vertex data into a buffer
787                        // Handle the offsets within Novus itself
788                        cursor
789                            .seek(SeekFrom::Start(
790                                (model.lods[i as usize].vertex_data_offset
791                                    + model.meshes[j as usize].vertex_buffer_offsets
792                                        [stream as usize]
793                                    + (z as u32 * stride as u32))
794                                    as u64,
795                            ))
796                            .ok()?;
797
798                        for _ in 0..stride {
799                            vertex_data.push(cursor.read_le::<u8>().ok()?);
800                        }
801                    }
802
803                    vertex_streams.push(vertex_data);
804                    vertex_stream_strides
805                        .push(mesh.vertex_buffer_strides[stream as usize] as usize);
806                }
807
808                parts.push(Part {
809                    mesh_index: j,
810                    vertices,
811                    indices,
812                    material_index,
813                    submeshes,
814                    shapes,
815                    vertex_streams,
816                    vertex_stream_strides,
817                });
818            }
819
820            lods.push(Lod { parts });
821        }
822
823        Some(MDL {
824            file_header: model_file_header,
825            model_data: model,
826            lods,
827            affected_bone_names,
828            material_names,
829        })
830    }
831
832    pub fn replace_vertices(
833        &mut self,
834        lod_index: usize,
835        part_index: usize,
836        vertices: &[Vertex],
837        indices: &[u16],
838        submeshes: &[SubMesh],
839    ) {
840        let part = &mut self.lods[lod_index].parts[part_index];
841
842        part.vertices = Vec::from(vertices);
843        part.indices = Vec::from(indices);
844
845        for (i, submesh) in part.submeshes.iter().enumerate() {
846            if i < submeshes.len() {
847                self.model_data.submeshes[submesh.submesh_index].index_offset =
848                    submeshes[i].index_offset;
849                self.model_data.submeshes[submesh.submesh_index].index_count =
850                    submeshes[i].index_count;
851            }
852        }
853
854        // Update vertex count in header
855        self.model_data.meshes[part.mesh_index as usize].vertex_count = part.vertices.len() as u16;
856        self.model_data.meshes[part.mesh_index as usize].index_count = part.indices.len() as u32;
857
858        self.update_headers();
859    }
860
861    pub fn remove_shape_meshes(&mut self) {
862        self.model_data.shape_meshes.clear();
863        self.model_data.shape_values.clear();
864
865        for lod in 0..3 {
866            for shape in &mut self.model_data.shapes {
867                shape.shape_mesh_count[lod] = 0;
868                shape.shape_mesh_start_index[lod] = 0;
869            }
870        }
871
872        self.update_headers();
873    }
874
875    pub fn add_shape_mesh(
876        &mut self,
877        lod_index: usize,
878        shape_index: usize,
879        shape_mesh_index: usize,
880        part_index: usize,
881        shape_values: &[NewShapeValue],
882    ) {
883        let part = &mut self.lods[lod_index].parts[part_index];
884
885        // TODO: this is assuming they are added in order
886        if shape_mesh_index == 0 {
887            self.model_data.shapes[shape_index].shape_mesh_start_index[lod_index] =
888                self.model_data.shape_meshes.len() as u16;
889        }
890
891        self.model_data.shape_meshes.push(ShapeMesh {
892            mesh_index_offset: self.model_data.meshes[part.mesh_index as usize].start_index,
893            shape_value_count: shape_values.len() as u32,
894            shape_value_offset: self.model_data.shape_values.len() as u32,
895        });
896
897        for shape_value in shape_values {
898            part.vertices.push(shape_value.replacing_vertex);
899
900            self.model_data.shape_values.push(ShapeValue {
901                base_indices_index: self.model_data.meshes[part.mesh_index as usize].start_index
902                    as u16
903                    + shape_value.base_index as u16,
904                replacing_vertex_index: self.model_data.meshes[part.mesh_index as usize].start_index
905                    as u16
906                    + (part.vertices.len() - 1) as u16,
907            })
908        }
909
910        self.model_data.shapes[shape_index].shape_mesh_count[lod_index] += 1;
911
912        self.update_headers();
913    }
914
915    pub(crate) fn update_headers(&mut self) {
916        // update values
917        for i in 0..self.file_header.lod_count {
918            let mut vertex_offset = 0;
919
920            for j in self.model_data.lods[i as usize].mesh_index
921                ..self.model_data.lods[i as usize].mesh_index
922                    + self.model_data.lods[i as usize].mesh_count
923            {
924                let mesh = &mut self.model_data.meshes[j as usize];
925
926                mesh.start_index =
927                    self.model_data.submeshes[mesh.submesh_index as usize].index_offset;
928
929                for i in 0..mesh.vertex_stream_count as usize {
930                    mesh.vertex_buffer_offsets[i] = vertex_offset;
931                    vertex_offset +=
932                        mesh.vertex_count as u32 * mesh.vertex_buffer_strides[i] as u32;
933                }
934            }
935        }
936
937        for lod in &mut self.model_data.lods {
938            let mut total_vertex_buffer_size = 0;
939            let mut total_index_buffer_size = 0;
940
941            // still slightly off?
942            for j in lod.mesh_index..lod.mesh_index + lod.mesh_count {
943                let vertex_count = self.model_data.meshes[j as usize].vertex_count;
944                let index_count = self.model_data.meshes[j as usize].index_count;
945
946                let mut total_vertex_stride: u32 = 0;
947                for i in 0..self.model_data.meshes[j as usize].vertex_stream_count as usize {
948                    total_vertex_stride +=
949                        self.model_data.meshes[j as usize].vertex_buffer_strides[i] as u32;
950                }
951
952                total_vertex_buffer_size += vertex_count as u32 * total_vertex_stride;
953                total_index_buffer_size += index_count * size_of::<u16>() as u32;
954            }
955
956            // TODO: this can definitely be written better
957            let mut index_padding = total_index_buffer_size % 16;
958            if index_padding == 0 {
959                index_padding = 16;
960            } else {
961                index_padding = 16 - index_padding;
962            }
963
964            lod.vertex_buffer_size = total_vertex_buffer_size;
965            lod.index_buffer_size = total_index_buffer_size.wrapping_add(index_padding);
966        }
967
968        // update lod values
969        self.file_header.stack_size = self.file_header.calculate_stack_size();
970        self.file_header.runtime_size = self.model_data.calculate_runtime_size();
971
972        let data_offset = self.file_header.runtime_size
973            + size_of::<ModelFileHeader>() as u32
974            + self.file_header.stack_size;
975
976        let mut overall_offset: u32 = 0;
977
978        for lod in &mut self.model_data.lods {
979            // vertex
980            lod.vertex_data_offset = data_offset + overall_offset;
981            overall_offset += lod.vertex_buffer_size;
982
983            // index
984            lod.index_data_offset = data_offset + overall_offset;
985            overall_offset += lod.index_buffer_size;
986
987            // edge, but unused?
988            //lod.edge_geometry_data_offset = data_offset + overall_offset;
989            //overall_offset += lod.edge_geometry_size;
990
991            lod.edge_geometry_data_offset = lod.index_data_offset;
992        }
993
994        for i in 0..self.lods.len() {
995            self.file_header.vertex_buffer_size[i] = self.model_data.lods[i].vertex_buffer_size;
996        }
997
998        for i in 0..self.lods.len() {
999            self.file_header.vertex_offsets[i] = self.model_data.lods[i].vertex_data_offset;
1000        }
1001
1002        for i in 0..self.lods.len() {
1003            self.file_header.index_buffer_size[i] = self.model_data.lods[i].index_buffer_size;
1004        }
1005
1006        for i in 0..self.lods.len() {
1007            self.file_header.index_offsets[i] = self.model_data.lods[i].index_data_offset;
1008        }
1009
1010        self.model_data.header.shape_count = self.model_data.shapes.len() as u16;
1011        self.model_data.header.shape_mesh_count = self.model_data.shape_meshes.len() as u16;
1012        self.model_data.header.shape_value_count = self.model_data.shape_values.len() as u16;
1013    }
1014
1015    pub fn write_to_buffer(&self) -> Option<ByteBuffer> {
1016        let mut buffer = ByteBuffer::new();
1017
1018        {
1019            let mut cursor = Cursor::new(&mut buffer);
1020
1021            // write file header
1022            self.file_header.write(&mut cursor).ok()?;
1023
1024            self.model_data.write(&mut cursor).ok()?;
1025
1026            for (l, lod) in self.lods.iter().enumerate() {
1027                for part in lod.parts.iter() {
1028                    let declaration =
1029                        &self.model_data.header.vertex_declarations[part.mesh_index as usize];
1030
1031                    for (k, vert) in part.vertices.iter().enumerate() {
1032                        for element in &declaration.elements {
1033                            cursor
1034                                .seek(SeekFrom::Start(
1035                                    (self.model_data.lods[l].vertex_data_offset
1036                                        + self.model_data.meshes[part.mesh_index as usize]
1037                                            .vertex_buffer_offsets
1038                                            [element.stream as usize]
1039                                        + element.offset as u32
1040                                        + self.model_data.meshes[part.mesh_index as usize]
1041                                            .vertex_buffer_strides
1042                                            [element.stream as usize]
1043                                            as u32
1044                                            * k as u32) as u64,
1045                                ))
1046                                .ok()?;
1047
1048                            match element.vertex_usage {
1049                                VertexUsage::Position => match element.vertex_type {
1050                                    VertexType::Single4 => {
1051                                        MDL::write_single4(
1052                                            &mut cursor,
1053                                            &MDL::pad_slice(&vert.position, 1.0),
1054                                        )
1055                                        .ok()?;
1056                                    }
1057                                    VertexType::Half4 => {
1058                                        MDL::write_half4(
1059                                            &mut cursor,
1060                                            &MDL::pad_slice(&vert.position, 1.0),
1061                                        )
1062                                        .ok()?;
1063                                    }
1064                                    VertexType::Single3 => {
1065                                        MDL::write_single3(&mut cursor, &vert.position).ok()?;
1066                                    }
1067                                    _ => {
1068                                        panic!(
1069                                            "Unexpected vertex type for position: {:#?}",
1070                                            element.vertex_type
1071                                        );
1072                                    }
1073                                },
1074                                VertexUsage::BlendWeights => match element.vertex_type {
1075                                    VertexType::ByteFloat4 => {
1076                                        MDL::write_byte_float4(&mut cursor, &vert.bone_weight)
1077                                            .ok()?;
1078                                    }
1079                                    VertexType::Byte4 => {
1080                                        MDL::write_byte_float42(&mut cursor, &vert.bone_weight)
1081                                            .ok()?; // TODO: WRONG!
1082                                    }
1083                                    _ => {
1084                                        panic!(
1085                                            "Unexpected vertex type for blendweight: {:#?}",
1086                                            element.vertex_type
1087                                        );
1088                                    }
1089                                },
1090                                VertexUsage::BlendIndices => match element.vertex_type {
1091                                    VertexType::Byte4 => {
1092                                        MDL::write_byte4(&mut cursor, &vert.bone_id).ok()?;
1093                                    }
1094                                    _ => {
1095                                        panic!(
1096                                            "Unexpected vertex type for blendindice: {:#?}",
1097                                            element.vertex_type
1098                                        );
1099                                    }
1100                                },
1101                                VertexUsage::Normal => match element.vertex_type {
1102                                    VertexType::Half4 => {
1103                                        MDL::write_half4(
1104                                            &mut cursor,
1105                                            &MDL::pad_slice(&vert.normal, 0.0),
1106                                        )
1107                                        .ok()?;
1108                                    }
1109                                    VertexType::Single3 => {
1110                                        MDL::write_single3(&mut cursor, &vert.normal).ok()?;
1111                                    }
1112                                    _ => {
1113                                        panic!(
1114                                            "Unexpected vertex type for normal: {:#?}",
1115                                            element.vertex_type
1116                                        );
1117                                    }
1118                                },
1119                                VertexUsage::UV => match element.vertex_type {
1120                                    VertexType::Half4 => {
1121                                        let combined =
1122                                            [vert.uv0[0], vert.uv0[1], vert.uv1[0], vert.uv1[1]];
1123
1124                                        MDL::write_half4(&mut cursor, &combined).ok()?;
1125                                    }
1126                                    VertexType::Single4 => {
1127                                        let combined =
1128                                            [vert.uv0[0], vert.uv0[1], vert.uv1[0], vert.uv1[1]];
1129
1130                                        MDL::write_single4(&mut cursor, &combined).ok()?;
1131                                    }
1132                                    _ => {
1133                                        panic!(
1134                                            "Unexpected vertex type for uv: {:#?}",
1135                                            element.vertex_type
1136                                        );
1137                                    }
1138                                },
1139                                VertexUsage::BiTangent => match element.vertex_type {
1140                                    VertexType::ByteFloat4 => {
1141                                        MDL::write_tangent(&mut cursor, &vert.bitangent).ok()?;
1142                                    }
1143                                    _ => {
1144                                        panic!(
1145                                            "Unexpected vertex type for bitangent: {:#?}",
1146                                            element.vertex_type
1147                                        );
1148                                    }
1149                                },
1150                                VertexUsage::Tangent => {
1151                                    #[allow(clippy::match_single_binding)] // TODO
1152                                    match element.vertex_type {
1153                                        /*VertexType::ByteFloat4 => {
1154                                            MDL::write_tangent(&mut cursor, &vert.binormal).ok()?;
1155                                        }*/
1156                                        _ => {
1157                                            panic!(
1158                                                "Unexpected vertex type for tangent: {:#?}",
1159                                                element.vertex_type
1160                                            );
1161                                        }
1162                                    }
1163                                }
1164                                VertexUsage::Color => match element.vertex_type {
1165                                    VertexType::ByteFloat4 => {
1166                                        MDL::write_byte_float4(&mut cursor, &vert.color).ok()?;
1167                                    }
1168                                    _ => {
1169                                        panic!(
1170                                            "Unexpected vertex type for color: {:#?}",
1171                                            element.vertex_type
1172                                        );
1173                                    }
1174                                },
1175                            }
1176                        }
1177                    }
1178
1179                    cursor
1180                        .seek(SeekFrom::Start(
1181                            (self.file_header.index_offsets[l]
1182                                + (self.model_data.meshes[part.mesh_index as usize].start_index
1183                                    * size_of::<u16>() as u32)) as u64,
1184                        ))
1185                        .ok()?;
1186
1187                    cursor.write_le(&part.indices).ok()?;
1188                }
1189            }
1190        }
1191
1192        Some(buffer)
1193    }
1194}
1195
1196impl ModelFileHeader {
1197    pub fn calculate_stack_size(&self) -> u32 {
1198        // From https://github.com/Ottermandias/Penumbra.GameData/blob/44021b93e6901c84b739bbf4d1c6350f4486cdbf/Files/MdlFile.cs#L11
1199        self.vertex_declaration_count as u32 * NUM_VERTICES * VERTEX_ELEMENT_SIZE as u32
1200    }
1201}
1202
1203// TODO: From Xande, need to be cleaned up :)
1204impl ModelData {
1205    pub fn calculate_runtime_size(&self) -> u32 {
1206        2   //StringCount
1207        + 2 // Unknown
1208        + 4 //StringSize
1209        + self.header.string_size
1210        + 56 //ModelHeader
1211        + (self.element_ids.len() as u32 * 32)
1212        + (3 * 60) // 3 Lods
1213        //+ ( /*file.ModelHeader.ExtraLodEnabled ? 40*/ 0 )
1214        + self.meshes.len() as u32 * 36
1215        + self.attribute_name_offsets.len() as u32 * size_of::<u32>() as u32
1216        + self.header.terrain_shadow_mesh_count as u32 * 20
1217        + self.header.submesh_count as u32 * 16
1218        + self.header.terrain_shadow_submesh_count as u32 * 10
1219        + self.material_name_offsets.len() as u32 * size_of::<u32>() as u32
1220        + self.bone_name_offsets.len() as u32 * size_of::<u32>() as u32
1221        + self.bone_tables.len() as u32 * 132
1222        + self.header.shape_count as u32 * 16
1223        + self.header.shape_mesh_count as u32 * 12
1224        + self.header.shape_value_count as u32 * 4
1225        + 4 // SubmeshBoneMapSize
1226        + self.submesh_bone_map.len() as u32 * 2
1227        + self.padding_amount as u32 + 1          // PaddingAmount and Padding
1228        + (4 * 32) // 4 BoundingBoxes
1229        + (self.header.bone_count as u32 * 32)
1230    }
1231}
1232
1233#[cfg(test)]
1234mod tests {
1235    use std::fs::read;
1236    use std::mem::size_of;
1237    use std::path::PathBuf;
1238
1239    use crate::model_vertex_declarations::VERTEX_ELEMENT_SIZE;
1240
1241    use super::*;
1242
1243    #[test]
1244    fn test_file_header_size() {
1245        assert_eq!(0x44, size_of::<ModelFileHeader>());
1246    }
1247
1248    #[test]
1249    fn test_vertex_element_size() {
1250        assert_eq!(8, VERTEX_ELEMENT_SIZE);
1251    }
1252
1253    #[test]
1254    fn test_stack_size() {
1255        let example_header = ModelFileHeader {
1256            version: 0,
1257            stack_size: 0,
1258            runtime_size: 0,
1259            vertex_declaration_count: 6,
1260            material_count: 0,
1261            vertex_offsets: [0; 3],
1262            index_offsets: [0; 3],
1263            vertex_buffer_size: [0; 3],
1264            index_buffer_size: [0; 3],
1265            lod_count: 0,
1266            index_buffer_streaming_enabled: false,
1267            has_edge_geometry: false,
1268        };
1269
1270        assert_eq!(816, example_header.calculate_stack_size());
1271
1272        let example_header2 = ModelFileHeader {
1273            version: 0,
1274            stack_size: 0,
1275            runtime_size: 0,
1276            vertex_declaration_count: 2,
1277            material_count: 0,
1278            vertex_offsets: [0; 3],
1279            index_offsets: [0; 3],
1280            vertex_buffer_size: [0; 3],
1281            index_buffer_size: [0; 3],
1282            lod_count: 0,
1283            index_buffer_streaming_enabled: false,
1284            has_edge_geometry: false,
1285        };
1286
1287        assert_eq!(272, example_header2.calculate_stack_size());
1288    }
1289
1290    #[test]
1291    fn test_update_headers() {
1292        let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1293        d.push("resources/tests");
1294        d.push("c0201e0038_top_zeroed.mdl");
1295
1296        let mut mdl = MDL::from_existing(&read(d).unwrap()).unwrap();
1297        let old_mdl = mdl.clone();
1298
1299        mdl.update_headers();
1300
1301        // There should be no changes
1302        assert_eq!(mdl.file_header, old_mdl.file_header);
1303        assert_eq!(mdl.model_data, old_mdl.model_data);
1304    }
1305
1306    #[test]
1307    fn test_update_vertices() {
1308        let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1309        d.push("resources/tests");
1310        d.push("c0201e0038_top_zeroed.mdl");
1311
1312        let mut mdl = MDL::from_existing(&read(d).unwrap()).unwrap();
1313        let old_mdl = mdl.clone();
1314
1315        for l in 0..old_mdl.lods.len() {
1316            for p in 0..old_mdl.lods[l].parts.len() {
1317                mdl.replace_vertices(
1318                    l,
1319                    p,
1320                    &old_mdl.lods[l].parts[p].vertices,
1321                    &old_mdl.lods[l].parts[p].indices,
1322                    &old_mdl.lods[l].parts[p].submeshes,
1323                );
1324            }
1325        }
1326
1327        // There should be no changes
1328        assert_eq!(mdl.file_header, old_mdl.file_header);
1329        assert_eq!(mdl.model_data, old_mdl.model_data);
1330    }
1331
1332    #[test]
1333    fn test_parsing() {
1334        let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1335        d.push("resources/tests");
1336        d.push("c0201e0038_top_zeroed.mdl");
1337
1338        let mdl = MDL::from_existing(&read(d).unwrap()).unwrap();
1339
1340        // file header
1341        assert_eq!(mdl.file_header.version, 16777221);
1342        assert_eq!(mdl.file_header.stack_size, 816);
1343        assert_eq!(
1344            mdl.file_header.stack_size,
1345            mdl.file_header.calculate_stack_size()
1346        );
1347        assert_eq!(mdl.file_header.runtime_size, 12544);
1348        assert_eq!(
1349            mdl.file_header.runtime_size,
1350            mdl.model_data.calculate_runtime_size()
1351        );
1352        assert_eq!(mdl.file_header.vertex_declaration_count, 6);
1353        assert_eq!(mdl.file_header.material_count, 2);
1354        assert_eq!(mdl.file_header.lod_count, 3);
1355        assert!(!mdl.file_header.index_buffer_streaming_enabled);
1356        assert!(!mdl.file_header.has_edge_geometry);
1357
1358        // model header
1359        assert_eq!(mdl.model_data.header.radius, 1.5340779);
1360    }
1361
1362    #[test]
1363    fn test_invalid() {
1364        let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
1365        d.push("resources/tests");
1366        d.push("random");
1367
1368        // Feeding it invalid data should not panic
1369        MDL::from_existing(&read(d).unwrap());
1370    }
1371}