use annotated_parser::{ForwardRef, parsers::byte::F16LE, prelude::*};
use super::types::*;
use crate::file_parsers::shared::annotated_parser::{U8Parser, take_arr_u8};
fn vertex(format_id: ForwardRef<u32>) -> (impl U8Parser<Output = DolmVertex>, impl Fn()) {
let (tex_coord0, c0) = F16LE
.repeat::<2>()
.configured(format_id.clone().map(|f| (*f >> 3) & 1 == 1));
let (tail_float, c1) = F16LE
.repeat::<2>()
.configured(ForwardRef::with_value(false));
let (skin_bones, c2) =
take_arr_u8::<4>().configured(format_id.clone().map(|f| (*f >> 2) & 1 == 1));
let (skin_weights, c3) =
take_arr_u8::<4>().configured(format_id.clone().map(|f| (*f >> 2) & 1 == 1));
let (skin_extra, c4) =
take_arr_u8::<4>().configured(format_id.clone().map(|f| (*f >> 1) & 1 == 1));
let (tex_coord1, c5) = F16LE
.repeat::<2>()
.configured(format_id.clone().map(|f| *f & 1 == 1));
let (extra_bit6, c6) =
take_arr_u8::<4>().configured(format_id.clone().map(|f| (*f >> 6) & 1 == 1));
let conf = move || {
c0();
c1();
c2();
c3();
c4();
c5();
c6();
};
let parser = (
f32::LE.repeat::<3>(),
i8::LE.repeat::<4>(),
i8::LE.repeat::<4>(),
tex_coord0,
tail_float,
skin_bones,
skin_weights,
skin_extra,
tex_coord1,
extra_bit6,
)
.map_silent(
|(
pos,
normal,
tangent,
tex_coord0,
tail_float,
skin_bones,
skin_weights,
skin_extra,
tex_coord1,
extra_vformat_6,
)| {
DolmVertex {
pos,
normal,
tangent,
tex_coord0,
tail_float,
skin_bones,
skin_weights,
skin_extra,
tex_coord1,
extra_vformat_6,
}
},
)
.trace("dolm_vertex");
(parser, conf)
}
pub fn index_buffer(
num_triangles: ForwardRef<u32>,
num_vertices: ForwardRef<u32>,
) -> impl U8Parser<Output = IndexBuffer> {
let num_triangles3 = num_triangles.map(|t| *t * 3);
(
u16::LE
.repeat_vec(num_triangles3.clone())
.map_silent(IndexBuffer::U16),
u32::LE
.repeat_vec(num_triangles3)
.map_silent(IndexBuffer::U32),
)
.dispatch(num_vertices.map(|counts| {
let index = match counts {
..=0xffff => 0,
0x10000.. => 1,
};
Some(index)
}))
.trace("index_buffer")
}
fn mesh(
vertex_format: ForwardRef<u32>,
num_shapes: ForwardRef<u16>,
temp_lod_extents: ForwardRef<[u32; 2]>,
) -> (impl U8Parser<Output = Mesh>, impl Fn()) {
let shape_extents = u32::LE
.repeat::<2>()
.map_silent(|[start_index, count_index]| DolmShapeExtents {
start_index,
count_index,
})
.repeat_vec(num_shapes)
.trace("shape_extents");
let temp_num_vertices = temp_lod_extents.clone().map(|[_, v]| *v);
let single_index_buffer = index_buffer(
temp_lod_extents.clone().map(|[t, _]| *t),
temp_num_vertices.clone(),
);
let (vertex, vertex_conf) = vertex(vertex_format);
let vertex_buffer = vertex.repeat_vec(temp_num_vertices);
let mesh = (shape_extents, single_index_buffer, vertex_buffer)
.map_silent(|(shape_extents, indices, vertices)| Mesh {
shape_extents,
indices,
vertices,
})
.trace("mesh");
(mesh, vertex_conf)
}
pub fn dolm() -> impl U8Parser<Output = Dolm> {
let c0h = u16::LE.trace("c0h").store();
let lod_count = u8::LE.store().trace("num_lods");
let shape_count = u16::LE.store().trace("num_shapes");
let vertex_format = u32::LE.trace("vertex_format").store();
let header_lod_extents = u32::LE
.repeat::<2>()
.repeat_vec(lod_count.output())
.trace("lod_extents")
.store();
let temp_lod_extents = ForwardRef::<[u32; 2]>::new_source();
let (mesh, mesh_conf) = mesh(
vertex_format.output(),
shape_count.output(),
temp_lod_extents.clone(),
);
let vertex_format = vertex_format.configuring(mesh_conf);
let lods = mesh
.parameterize(header_lod_extents.output(), temp_lod_extents)
.trace("lods");
let extra_vformat_6 = take_arr_u8::<36>()
.repeat_vec(shape_count.output())
.run_if(vertex_format.output().map(|v| (*v >> 6) & 1 == 1));
let extra_vformat_6_c0h_2 = take_arr_u8::<4>().repeat_vec(shape_count.output()).run_if(
(c0h.output(), vertex_format.output()).map(|(c0h, vf)| *c0h == 2 && (*vf >> 6) & 1 == 1),
);
let extra_c0h_4 = take_arr_u8::<4>().run_if(
(c0h.output(), lod_count.output()).map(|(c0h, num_lods)| *c0h == 4 && *num_lods > 0),
);
(
b"DOLm",
c0h,
lod_count,
shape_count,
vertex_format,
header_lod_extents,
lods,
extra_vformat_6,
extra_vformat_6_c0h_2,
extra_c0h_4,
)
.map_silent(
|(
_magic,
c0h,
_lod_count,
_shape_count,
vertex_format_id,
lod_extents,
lods,
extra_vformat_6,
extra_vformat_6_c0h_2,
extra_c0h_4,
)| Dolm {
c0h,
vertex_format: vertex_format_id,
lod_extents,
lods,
extra_vformat_6,
extra_vformat_6_c0h_2,
extra_c0h_4,
},
)
.trace("dolm")
}