2022-07-28 14:11:02 -04:00
|
|
|
use crate::gamedata::MemoryBuffer;
|
2022-10-13 16:03:46 -04:00
|
|
|
use binrw::{binread, Endian, ReadOptions};
|
2022-08-16 11:52:07 -04:00
|
|
|
use binrw::binrw;
|
|
|
|
use binrw::BinRead;
|
2022-07-28 14:11:02 -04:00
|
|
|
use half::f16;
|
2022-08-16 11:52:07 -04:00
|
|
|
use std::io::{Cursor, Seek, SeekFrom};
|
2022-07-19 19:29:41 -04:00
|
|
|
|
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-10-13 16:03:46 -04:00
|
|
|
#[brw(little)]
|
2022-07-28 14:11:02 -04:00
|
|
|
pub struct ModelFileHeader {
|
2022-07-19 19:29:41 -04:00
|
|
|
pub(crate) version: u32,
|
|
|
|
|
|
|
|
pub stack_size: u32,
|
|
|
|
pub runtime_size: u32,
|
|
|
|
|
|
|
|
pub vertex_declaration_count: u16,
|
|
|
|
pub material_count: u16,
|
|
|
|
|
|
|
|
pub vertex_offsets: [u32; 3],
|
|
|
|
pub index_offsets: [u32; 3],
|
|
|
|
pub vertex_buffer_size: [u32; 3],
|
|
|
|
pub index_buffer_size: [u32; 3],
|
|
|
|
|
|
|
|
pub lod_count: u8,
|
|
|
|
|
|
|
|
#[br(map = | x: u8 | x != 0)]
|
|
|
|
#[bw(map = | x: & bool | -> u8 { if * x { 1 } else { 0 } })]
|
|
|
|
pub index_buffer_streaming_enabled: bool,
|
|
|
|
#[br(map = | x: u8 | x != 0)]
|
|
|
|
#[bw(map = | x: & bool | -> u8 { if * x { 1 } else { 0 } })]
|
|
|
|
#[brw(pad_after = 1)]
|
|
|
|
pub has_edge_geometry: bool,
|
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
|
|
|
#[brw(repr = u8)]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum ModelFlags1 {
|
|
|
|
DustOcclusionEnabled = 0x80,
|
|
|
|
SnowOcclusionEnabled = 0x40,
|
|
|
|
RainOcclusionEnabled = 0x20,
|
|
|
|
Unknown1 = 0x10,
|
|
|
|
LightingReflectionEnabled = 0x08,
|
|
|
|
WavingAnimationDisabled = 0x04,
|
|
|
|
LightShadowDisabled = 0x02,
|
2022-08-16 11:52:07 -04:00
|
|
|
ShadowDisabled = 0x01,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
|
|
|
#[brw(repr = u8)]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum ModelFlags2 {
|
|
|
|
None = 0x0,
|
|
|
|
Unknown2 = 0x80,
|
|
|
|
BgUvScrollEnabled = 0x40,
|
|
|
|
EnableForceNonResident = 0x20,
|
|
|
|
ExtraLodEnabled = 0x10,
|
|
|
|
ShadowMaskEnabled = 0x08,
|
|
|
|
ForceLodRangeEnabled = 0x04,
|
|
|
|
EdgeGeometryEnabled = 0x02,
|
2022-08-16 11:52:07 -04:00
|
|
|
Unknown3 = 0x01,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
pub struct ModelHeader {
|
|
|
|
#[br(pad_after = 2)]
|
2022-08-16 11:52:07 -04:00
|
|
|
string_count: u16,
|
|
|
|
string_size: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = string_size)]
|
2022-08-16 11:52:07 -04:00
|
|
|
strings: Vec<u8>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
radius: f32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
mesh_count: u16,
|
|
|
|
attribute_count: u16,
|
|
|
|
submesh_count: u16,
|
|
|
|
material_count: u16,
|
|
|
|
bone_count: u16,
|
|
|
|
bone_table_count: u16,
|
|
|
|
shape_count: u16,
|
|
|
|
shape_mesh_count: u16,
|
|
|
|
shape_value_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
lod_count: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
flags1: ModelFlags1,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
element_id_count: u16,
|
|
|
|
terrain_shadow_mesh_count: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(err_context("radius = {}", radius))]
|
2022-08-16 11:52:07 -04:00
|
|
|
flags2: ModelFlags2,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
model_clip_out_of_distance: f32,
|
|
|
|
shadow_clip_out_of_distance: f32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(pad_before = 2)]
|
|
|
|
#[br(pad_after = 2)]
|
2022-08-16 11:52:07 -04:00
|
|
|
terrain_shadow_submesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
bg_change_material_index: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
#[br(pad_after = 12)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bg_crest_change_material_index: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct MeshLod {
|
2022-08-16 11:52:07 -04:00
|
|
|
mesh_index: u16,
|
|
|
|
mesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
model_lod_range: f32,
|
|
|
|
texture_lod_range: f32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
water_mesh_index: u16,
|
|
|
|
water_mesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
shadow_mesh_index: u16,
|
|
|
|
shadow_mesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
terrain_shadow_mesh_count: u16,
|
|
|
|
terrain_shadow_mesh_index: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
vertical_fog_mesh_index: u16,
|
|
|
|
vertical_fog_mesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
// unused on win32 according to lumina devs
|
2022-08-16 11:52:07 -04:00
|
|
|
edge_geometry_size: u32,
|
|
|
|
edge_geometry_data_offset: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(pad_after = 4)]
|
2022-08-16 11:52:07 -04:00
|
|
|
polygon_count: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
vertex_buffer_size: u32,
|
|
|
|
index_buffer_size: u32,
|
|
|
|
vertex_data_offset: u32,
|
|
|
|
index_data_offset: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct Mesh {
|
|
|
|
#[br(pad_after = 2)]
|
2022-08-16 11:52:07 -04:00
|
|
|
vertex_count: u16,
|
|
|
|
index_count: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
material_index: u16,
|
|
|
|
submesh_index: u16,
|
|
|
|
submesh_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_table_index: u16,
|
|
|
|
start_index: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
vertex_buffer_offsets: [u32; 3],
|
|
|
|
vertex_buffer_strides: [u8; 3],
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
vertex_stream_count: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct Submesh {
|
2022-08-16 11:52:07 -04:00
|
|
|
index_offset: i32,
|
|
|
|
index_count: i32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
attribute_index_mask: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_start_index: u16,
|
|
|
|
bone_count: u16,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct BoneTable {
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_indices: [u16; 64],
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(pad_after = 3)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_count: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct BoundingBox {
|
2022-08-16 11:52:07 -04:00
|
|
|
min: [f32; 4],
|
|
|
|
max: [f32; 4],
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-10-13 17:11:03 -04:00
|
|
|
#[brw(little)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct ModelData {
|
2022-08-16 11:52:07 -04:00
|
|
|
header: ModelHeader,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.element_id_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
element_ids: Vec<ElementId>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = 3)]
|
2022-08-16 11:52:07 -04:00
|
|
|
lods: Vec<MeshLod>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.mesh_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
meshes: Vec<Mesh>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.attribute_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
attribute_name_offsets: Vec<u32>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
// TODO: implement terrain shadow meshes
|
|
|
|
#[br(count = header.submesh_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
submeshes: Vec<Submesh>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
// TODO: implement terrain shadow submeshes
|
|
|
|
#[br(count = header.material_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
material_name_offsets: Vec<u32>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.bone_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_name_offsets: Vec<u32>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.bone_table_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_tables: Vec<BoneTable>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
// TODO: implement shapes
|
|
|
|
#[br(temp)]
|
2022-10-13 17:11:03 -04:00
|
|
|
#[bw(ignore)]
|
2022-08-16 11:52:07 -04:00
|
|
|
submesh_bone_map_size: u32,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = submesh_bone_map_size / 2, err_context("lods = {:#?}", lods))]
|
2022-08-16 11:52:07 -04:00
|
|
|
submesh_bone_map: Vec<u16>,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(temp)]
|
2022-10-13 17:11:03 -04:00
|
|
|
#[bw(ignore)]
|
2022-08-16 11:52:07 -04:00
|
|
|
padding_amount: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(pad_before = padding_amount)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bounding_box: BoundingBox,
|
|
|
|
model_bounding_box: BoundingBox,
|
|
|
|
water_bounding_box: BoundingBox,
|
|
|
|
vertical_fog_bounding_box: BoundingBox,
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
#[br(count = header.bone_count)]
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_bounding_boxes: Vec<BoundingBox>,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct ElementId {
|
2022-08-16 11:52:07 -04:00
|
|
|
element_id: u32,
|
|
|
|
parent_bone_name: u32,
|
|
|
|
translate: [f32; 3],
|
|
|
|
rotate: [f32; 3],
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
|
|
|
#[brw(repr = u8)]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
|
enum VertexType {
|
|
|
|
Invalid = 0,
|
|
|
|
Single3 = 2,
|
|
|
|
Single4 = 3,
|
|
|
|
UInt = 5,
|
|
|
|
ByteFloat4 = 8,
|
|
|
|
Half2 = 13,
|
2022-08-16 11:52:07 -04:00
|
|
|
Half4 = 14,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
|
|
|
#[brw(repr = u8)]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
enum VertexUsage {
|
|
|
|
Position = 0,
|
|
|
|
BlendWeights = 1,
|
|
|
|
BlendIndices = 2,
|
|
|
|
Normal = 3,
|
|
|
|
UV = 4,
|
|
|
|
Tangent2 = 5,
|
|
|
|
Tangent1 = 6,
|
|
|
|
Color = 7,
|
|
|
|
}
|
|
|
|
|
2022-10-13 17:11:03 -04:00
|
|
|
#[binrw]
|
2022-07-28 14:11:02 -04:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2022-09-15 16:26:31 -04:00
|
|
|
#[allow(dead_code)]
|
2022-10-13 17:11:03 -04:00
|
|
|
#[brw(little)]
|
2022-07-28 14:11:02 -04:00
|
|
|
struct VertexElement {
|
2022-08-16 11:52:07 -04:00
|
|
|
stream: u8,
|
|
|
|
offset: u8,
|
|
|
|
vertex_type: VertexType,
|
|
|
|
vertex_usage: VertexUsage,
|
2022-07-28 14:11:02 -04:00
|
|
|
#[br(pad_after = 3)]
|
2022-08-16 11:52:07 -04:00
|
|
|
usage_index: u8,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2022-07-28 15:20:47 -04:00
|
|
|
#[repr(C)]
|
2022-07-28 14:11:02 -04:00
|
|
|
pub struct Vertex {
|
2022-08-16 11:52:07 -04:00
|
|
|
pub position: [f32; 3],
|
2022-07-28 15:20:47 -04:00
|
|
|
pub uv: [f32; 2],
|
|
|
|
pub normal: [f32; 3],
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-07-28 15:20:47 -04:00
|
|
|
pub bone_weight: [f32; 4],
|
2022-08-16 11:52:07 -04:00
|
|
|
pub bone_id: [u8; 4],
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Part {
|
2022-08-16 11:52:07 -04:00
|
|
|
pub vertices: Vec<Vertex>,
|
|
|
|
pub indices: Vec<u16>,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Lod {
|
2022-08-16 11:52:07 -04:00
|
|
|
pub parts: Vec<Part>,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MDL {
|
2022-08-16 11:52:07 -04:00
|
|
|
pub lods: Vec<Lod>,
|
|
|
|
pub affected_bone_names: Vec<String>,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MDL {
|
2022-08-16 11:52:07 -04:00
|
|
|
pub fn from_existing(buffer: &MemoryBuffer) -> Option<MDL> {
|
2022-07-28 14:11:02 -04:00
|
|
|
let mut cursor = Cursor::new(buffer);
|
|
|
|
let model_file_header = ModelFileHeader::read(&mut cursor).unwrap();
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
struct VertexDeclaration {
|
2022-08-16 11:52:07 -04:00
|
|
|
elements: Vec<VertexElement>,
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
let mut vertex_declarations: Vec<VertexDeclaration> =
|
|
|
|
vec![
|
|
|
|
VertexDeclaration { elements: vec![] };
|
|
|
|
model_file_header.vertex_declaration_count as usize
|
|
|
|
];
|
2022-08-06 18:07:42 -04:00
|
|
|
for declaration in &mut vertex_declarations {
|
2022-07-28 14:11:02 -04:00
|
|
|
let mut element = VertexElement::read(&mut cursor).unwrap();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
declaration.elements.push(element);
|
|
|
|
|
|
|
|
element = VertexElement::read(&mut cursor).unwrap();
|
|
|
|
|
|
|
|
if element.stream == 255 {
|
|
|
|
break;
|
|
|
|
}
|
2022-08-16 11:52:07 -04:00
|
|
|
}
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
let to_seek = 17 * 8 - (declaration.elements.len() + 1) * 8;
|
2022-08-06 18:07:42 -04:00
|
|
|
cursor.seek(SeekFrom::Current(to_seek as i64)).ok()?;
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let model = ModelData::read(&mut cursor).unwrap();
|
|
|
|
|
2022-08-10 14:51:50 -04:00
|
|
|
let mut affected_bone_names = vec![];
|
|
|
|
|
|
|
|
for mut offset in model.bone_name_offsets {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
affected_bone_names.push(string);
|
|
|
|
}
|
|
|
|
|
2022-07-28 14:11:02 -04:00
|
|
|
let mut lods = vec![];
|
|
|
|
|
|
|
|
for i in 0..model.header.lod_count {
|
|
|
|
let mut parts = vec![];
|
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
for j in model.lods[i as usize].mesh_index
|
|
|
|
..model.lods[i as usize].mesh_index + model.lods[i as usize].mesh_count
|
|
|
|
{
|
2022-07-28 14:11:02 -04:00
|
|
|
let declaration = &vertex_declarations[j as usize];
|
|
|
|
let vertex_count = model.meshes[j as usize].vertex_count;
|
|
|
|
|
|
|
|
let default_vertex = Vertex {
|
|
|
|
position: [0.0; 3],
|
|
|
|
uv: [0.0; 2],
|
|
|
|
normal: [0.0; 3],
|
|
|
|
bone_weight: [0.0; 4],
|
2022-08-16 11:52:07 -04:00
|
|
|
bone_id: [0u8; 4],
|
2022-07-28 14:11:02 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut vertices: Vec<Vertex> = vec![default_vertex; vertex_count as usize];
|
|
|
|
|
|
|
|
for k in 0..vertex_count {
|
|
|
|
for element in &declaration.elements {
|
2022-08-16 11:52:07 -04:00
|
|
|
cursor
|
|
|
|
.seek(SeekFrom::Start(
|
|
|
|
(model.lods[i as usize].vertex_data_offset
|
|
|
|
+ model.meshes[j as usize].vertex_buffer_offsets
|
|
|
|
[element.stream as usize]
|
|
|
|
+ element.offset as u32
|
|
|
|
+ model.meshes[i as usize].vertex_buffer_strides
|
|
|
|
[element.stream as usize]
|
|
|
|
as u32
|
|
|
|
* k as u32) as u64,
|
|
|
|
))
|
|
|
|
.ok()?;
|
2022-07-28 14:11:02 -04:00
|
|
|
|
2022-10-13 16:11:20 -04:00
|
|
|
let options = ReadOptions::new(Endian::Little);
|
2022-10-13 16:03:46 -04:00
|
|
|
|
2022-07-28 14:11:02 -04:00
|
|
|
match element.vertex_usage {
|
|
|
|
VertexUsage::Position => {
|
2022-08-16 11:52:07 -04:00
|
|
|
vertices[k as usize].position =
|
2022-10-13 16:03:46 -04:00
|
|
|
<[f32; 3]>::read_options(&mut cursor, &options, ()).unwrap();
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
VertexUsage::BlendWeights => {
|
2022-08-16 11:52:07 -04:00
|
|
|
vertices[k as usize].bone_weight =
|
2022-10-13 16:03:46 -04:00
|
|
|
<[f32; 4]>::read_options(&mut cursor, &options, ()).unwrap();
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
VertexUsage::BlendIndices => {
|
2022-08-16 11:52:07 -04:00
|
|
|
vertices[k as usize].bone_id =
|
|
|
|
<[u8; 4]>::read(&mut cursor).unwrap();
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
VertexUsage::Normal => {
|
2022-08-05 18:23:52 -04:00
|
|
|
// TODO: normals are assumed to be half4
|
2022-08-16 11:52:07 -04:00
|
|
|
vertices[k as usize].normal[0] =
|
2022-10-13 16:03:46 -04:00
|
|
|
f16::from_bits(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap())
|
2022-08-16 11:52:07 -04:00
|
|
|
.to_f32();
|
|
|
|
vertices[k as usize].normal[1] =
|
2022-10-13 16:03:46 -04:00
|
|
|
f16::from_bits(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap())
|
2022-08-16 11:52:07 -04:00
|
|
|
.to_f32();
|
|
|
|
vertices[k as usize].normal[2] =
|
2022-10-13 16:03:46 -04:00
|
|
|
f16::from_bits(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap())
|
2022-08-16 11:52:07 -04:00
|
|
|
.to_f32();
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
VertexUsage::UV => {
|
2022-08-16 11:52:07 -04:00
|
|
|
vertices[k as usize].uv[0] =
|
2022-10-13 16:03:46 -04:00
|
|
|
f16::from_bits(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap())
|
2022-08-16 11:52:07 -04:00
|
|
|
.to_f32();
|
|
|
|
vertices[k as usize].uv[1] =
|
2022-10-13 16:03:46 -04:00
|
|
|
f16::from_bits(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap())
|
2022-08-16 11:52:07 -04:00
|
|
|
.to_f32();
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
VertexUsage::Tangent2 => {}
|
|
|
|
VertexUsage::Tangent1 => {}
|
|
|
|
VertexUsage::Color => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
cursor
|
|
|
|
.seek(SeekFrom::Start(
|
|
|
|
(model_file_header.index_offsets[i as usize]
|
|
|
|
+ (model.meshes[j as usize].start_index * 2))
|
|
|
|
as u64,
|
|
|
|
))
|
|
|
|
.ok()?;
|
2022-07-28 14:11:02 -04:00
|
|
|
|
|
|
|
// TODO: optimize!
|
2022-08-16 11:52:07 -04:00
|
|
|
let mut indices: Vec<u16> =
|
|
|
|
Vec::with_capacity(model.meshes[j as usize].index_count as usize);
|
2022-08-06 18:07:42 -04:00
|
|
|
for _ in 0..model.meshes[j as usize].index_count {
|
2022-10-13 16:11:20 -04:00
|
|
|
let options = ReadOptions::new(Endian::Little);
|
2022-10-13 16:03:46 -04:00
|
|
|
indices.push(<u16 as BinRead>::read_options(&mut cursor, &options, ()).unwrap());
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
parts.push(Part { vertices, indices });
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
|
|
|
|
2022-08-16 11:52:07 -04:00
|
|
|
lods.push(Lod { parts });
|
2022-07-28 14:11:02 -04:00
|
|
|
}
|
2022-07-19 19:29:41 -04:00
|
|
|
|
2022-07-28 14:11:02 -04:00
|
|
|
Some(MDL {
|
2022-08-10 14:51:50 -04:00
|
|
|
lods,
|
2022-08-16 11:52:07 -04:00
|
|
|
affected_bone_names,
|
2022-07-28 14:11:02 -04:00
|
|
|
})
|
|
|
|
}
|
2022-08-16 11:52:07 -04:00
|
|
|
}
|