1use crate::{
14 msrd::Streaming,
15 parse_count32_offset32, parse_offset32_count32, parse_opt_ptr32, parse_ptr32,
16 parse_string_opt_ptr32, parse_string_ptr32,
17 spch::Spch,
18 vertex::{DataType, VertexData},
19 xc3_write_binwrite_impl, StringOffset32,
20};
21use bilge::prelude::*;
22use binrw::{args, binread, BinRead, BinWrite};
23use legacy2::MxmdV40;
24use xc3_write::{Xc3Write, Xc3WriteOffsets};
25
26pub mod legacy;
27pub mod legacy2;
28
29#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
30#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
31#[br(magic(b"DMXM"))]
32#[xc3(magic(b"DMXM"))]
33pub struct Mxmd {
34 pub version: u32,
36
37 #[br(args_raw(version))]
38 pub inner: MxmdInner,
39}
40
41#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
42#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
43#[br(import_raw(version: u32))]
44pub enum MxmdInner {
45 #[br(pre_assert(version == 10040))]
46 V40(MxmdV40),
47
48 #[br(pre_assert(version == 10111))]
49 V111(MxmdV111),
50
51 #[br(pre_assert(version == 10112))]
52 V112(MxmdV112),
53}
54
55#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
57#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
58pub struct MxmdV111 {
59 #[br(parse_with = parse_ptr32)]
61 #[xc3(offset(u32))]
62 pub models: ModelsV111,
63
64 #[br(parse_with = parse_ptr32)]
66 #[xc3(offset(u32))]
67 pub materials: Materials,
68
69 #[br(parse_with = parse_opt_ptr32)]
70 #[xc3(offset(u32))]
71 pub unk1: Option<Unk1>,
72
73 #[br(parse_with = parse_opt_ptr32)]
76 #[xc3(offset(u32))]
77 pub vertex_data: Option<VertexData>,
78
79 #[br(parse_with = parse_opt_ptr32)]
81 #[xc3(offset(u32))]
82 pub spch: Option<Spch>,
83
84 #[br(parse_with = parse_opt_ptr32)]
86 #[xc3(offset(u32))]
87 pub packed_textures: Option<PackedTextures>,
88
89 pub unk5: u32,
90
91 #[br(parse_with = parse_opt_ptr32)]
94 #[xc3(offset(u32), align(4))]
95 pub streaming: Option<Streaming>,
96
97 pub unk6: u32,
98 pub unk7: u32,
99
100 #[br(parse_with = parse_opt_ptr32)]
101 #[xc3(offset(u32), align(16))]
102 pub unk8: Option<Unk8>,
103
104 pub unk: [u32; 6],
106}
107
108#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
109#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
110pub struct MxmdV112 {
111 #[br(parse_with = parse_ptr32)]
113 #[xc3(offset(u32), align(16))]
114 pub models: ModelsV112,
115
116 #[br(parse_with = parse_ptr32)]
118 #[xc3(offset(u32), align(16))]
119 pub materials: Materials,
120
121 #[br(parse_with = parse_opt_ptr32)]
122 #[xc3(offset(u32), align(16))]
123 pub unk1: Option<Unk1>,
124
125 #[br(parse_with = parse_opt_ptr32)]
127 #[xc3(offset(u32))]
128 pub vertex_data: Option<VertexData>,
129
130 #[br(parse_with = parse_opt_ptr32)]
132 #[xc3(offset(u32))]
133 pub spch: Option<Spch>,
134
135 #[br(parse_with = parse_opt_ptr32)]
137 #[xc3(offset(u32))]
138 pub packed_textures: Option<PackedTextures>,
139
140 pub unk5: u32,
141
142 #[br(parse_with = parse_opt_ptr32)]
145 #[xc3(offset(u32), align(4))]
146 pub streaming: Option<Streaming>,
147
148 pub unk6: u32,
149 pub unk7: u32,
150
151 #[br(parse_with = parse_opt_ptr32)]
152 #[xc3(offset(u32), align(16))]
153 pub unk8: Option<Unk8>,
154
155 pub unk: [u32; 6],
157}
158
159#[binread]
164#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
165#[derive(Debug, Xc3Write, PartialEq, Clone)]
166#[br(stream = r)]
167#[xc3(base_offset)]
168pub struct Materials {
169 #[br(temp, try_calc = r.stream_position())]
170 base_offset: u64,
171
172 #[br(temp, restore_position)]
173 material_offset: u32,
174
175 #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
177 #[xc3(offset_count(u32, u32), align(4))]
178 pub materials: Vec<Material>,
179
180 pub unk1: u32,
182 pub unk2: u32,
183
184 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
187 #[xc3(offset_count(u32, u32), align(16))]
188 pub work_values: Vec<f32>,
189
190 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
193 #[xc3(offset_count(u32, u32))]
194 pub shader_vars: Vec<(u16, u16)>, #[br(parse_with = parse_opt_ptr32)]
197 #[br(args { offset: base_offset, inner: base_offset })]
198 #[xc3(offset(u32))]
199 pub callbacks: Option<MaterialCallbacks>,
200
201 pub unk4: u32,
203
204 #[br(parse_with = parse_offset32_count32)]
206 #[br(args { offset: base_offset, inner: base_offset })]
207 #[xc3(offset_count(u32, u32))]
208 pub techniques: Vec<Technique>,
209
210 pub unks1: u32,
211
212 #[br(parse_with = parse_opt_ptr32)]
213 #[br(args { offset: base_offset, inner: base_offset })]
214 #[xc3(offset(u32))]
215 pub unk6: Option<MaterialUnk6>,
216
217 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
218 #[xc3(count_offset(u32, u32))]
219 pub alpha_test_textures: Vec<AlphaTestTexture>,
220
221 pub unks3: [u32; 3],
223
224 #[br(parse_with = parse_opt_ptr32)]
225 #[br(args { offset: base_offset, inner: base_offset })]
226 #[xc3(offset(u32))]
227 pub material_unk2: Option<MaterialUnk2>,
228
229 #[br(parse_with = parse_opt_ptr32)]
230 #[br(args { offset: base_offset, inner: args! { base_offset, count: materials.len() } })]
231 #[xc3(offset(u32))]
232 pub fur_shells: Option<FurShells>,
233
234 pub unks3_1: [u32; 2],
235
236 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
237 #[xc3(offset(u32))]
238 pub samplers: Option<Samplers>,
239
240 pub unks4: [u32; 3],
242
243 #[br(if(material_offset >= 112))]
244 #[br(args_raw(base_offset))]
245 pub unk5: Option<MaterialUnk5>,
246}
247
248#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
249#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
250pub struct AlphaTestTexture {
251 pub texture_index: u16,
254 pub sampler_index: u16,
256
257 pub unk2: u16, pub unk3: u16, }
261
262#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
264#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
265#[br(import_raw(base_offset: u64))]
266pub struct Technique {
267 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
270 #[xc3(offset_count(u32, u32))]
271 pub attributes: Vec<VertexAttribute>,
272
273 pub unk3: u32, pub unk4: u32, #[br(parse_with = parse_offset32_count32, offset = base_offset)]
279 #[xc3(offset_count(u32, u32))]
280 pub parameters: Vec<MaterialParameter>,
281
282 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
283 #[xc3(offset_count(u32, u32))]
284 pub textures: Vec<u16>,
285
286 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
288 #[xc3(offset_count(u32, u32))]
289 pub uniform_blocks: Vec<UniformBlock>, pub material_texture_count: u32,
292
293 pub unk12: u16, pub unk13: u16, pub unk14: u32,
299
300 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
302 #[xc3(offset_count(u32, u32))]
303 pub unk15: Vec<[u32; 5]>,
304
305 pub padding: [u32; 2],
307}
308
309#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
310#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
311pub struct UniformBlock {
312 pub unk1: u16,
313 pub unk2: u8,
314 pub unk3: u8,
315}
316
317#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
318#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
319pub struct VertexAttribute {
320 pub data_type: DataType,
321 pub relative_offset: u16,
322 pub buffer_index: u16,
323 pub unk4: u16, }
325
326#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
328#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
329pub struct MaterialParameter {
330 pub param_type: ParamType,
331 pub work_value_index: u16, pub unk: u16,
333 pub count: u16, }
337
338#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
339#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
340#[brw(repr(u16))]
341pub enum ParamType {
342 DpRat = 0,
344 TexMatrix = 1,
347 WorkFloat4 = 2,
350 WorkColor = 3,
353 ProjectionTexMatrix = 4,
355 AlphaInfo = 5,
358 MaterialColor = 6,
361 Unk7 = 7,
362 ToonHeadMatrix = 10,
364}
365
366#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
367#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
368#[br(import_raw(base_offset: u64))]
369pub struct MaterialCallbacks {
370 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
372 #[xc3(offset_count(u32, u32))]
373 pub work_callbacks: Vec<WorkCallback>,
374
375 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
377 #[xc3(offset_count(u32, u32))]
378 pub material_indices: Vec<u16>,
379
380 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
382 #[xc3(offset_count(u32, u32))]
383 pub unk1: Vec<[u32; 2]>,
384
385 pub unk: [u32; 6],
387}
388
389#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
390#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
391pub struct WorkCallback {
392 pub unk1: u16,
396 pub unk2: u16,
398}
399
400#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
401#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
402#[br(import_raw(base_offset: u64))]
403pub struct MaterialUnk2 {
404 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
405 #[xc3(count_offset(u32, u32))]
406 pub unk1: Vec<[u32; 3]>,
407
408 pub unk: [u32; 4],
410}
411
412#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
413#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
414#[br(import { base_offset: u64, count: usize })]
415pub struct FurShells {
416 #[br(parse_with = parse_ptr32)]
419 #[br(args { offset: base_offset, inner: args! { count }})]
420 #[xc3(offset(u32))]
421 pub material_param_indices: Vec<u16>,
422
423 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
424 #[xc3(offset_count(u32, u32))]
425 pub params: Vec<FurShellParams>,
426
427 pub unk: [u32; 4],
429}
430
431#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
432#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
433pub struct FurShellParams {
434 pub instance_count: u32,
436 pub view_distance: f32,
438 pub shell_width: f32,
440 pub y_offset: f32,
442 pub alpha: f32,
445}
446
447#[binread]
449#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
450#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
451#[br(stream = r)]
452#[xc3(base_offset)]
453pub struct Samplers {
454 #[br(temp, try_calc = r.stream_position())]
455 base_offset: u64,
456
457 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
458 #[xc3(count_offset(u32, u32))]
459 pub samplers: Vec<Sampler>,
460
461 pub unk: [u32; 2],
463}
464
465#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
467#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
468pub struct Sampler {
469 pub flags: SamplerFlags,
470 pub unk2: u16,
471
472 pub unk3: f32,
474}
475
476#[bitsize(16)]
478#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
479#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
480#[br(map = u16::into)]
481#[bw(map = |&x| u16::from(x))]
482pub struct SamplerFlags {
483 pub repeat_u: bool,
485 pub repeat_v: bool,
487 pub mirror_u: bool,
489 pub mirror_v: bool,
491 pub nearest: bool,
495 pub force_clamp: bool,
498 pub disable_mipmap_filter: bool,
501 pub unk1: bool,
502 pub unk3: bool,
503 pub unk: u7,
504}
505
506#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
509#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
510#[br(import_raw(base_offset: u64))]
511pub struct Material {
512 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
513 #[xc3(offset(u32))]
514 pub name: String,
515
516 pub flags: MaterialFlags,
517
518 pub render_flags: MaterialRenderFlags,
519
520 pub color: [f32; 4],
522
523 pub alpha_test_ref: f32,
525
526 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
529 #[xc3(offset_count(u32, u32))]
530 pub textures: Vec<Texture>,
531
532 pub state_flags: StateFlags,
534
535 pub m_unks1_1: u32,
537 pub m_unks1_2: u32,
538 pub m_unks1_3: u32,
539 pub m_unks1_4: u32,
540
541 pub work_value_start_index: u32,
544
545 pub shader_var_start_index: u32,
548 pub shader_var_count: u32,
549
550 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
552 #[xc3(offset_count(u32, u32))]
553 pub techniques: Vec<MaterialTechnique>,
554
555 pub unk5: u32, pub callback_start_index: u16,
559 pub callback_count: u16,
560
561 pub m_unks2: [u16; 3],
563
564 pub alpha_test_texture_index: u16,
566
567 pub m_unk3: u16,
568
569 pub gbuffer_flags: u16, pub m_unk4: [u16; 6],
573}
574
575#[bitsize(32)]
576#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
577#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
578#[br(map = u32::into)]
579#[bw(map = |&x| u32::from(x))]
580pub struct MaterialFlags {
581 pub unk1: bool,
582 pub unk2: bool,
583 pub alpha_mask: bool,
585 pub separate_mask: bool,
588 pub unk5: bool,
589 pub unk6: bool,
590 pub unk7: bool,
591 pub unk8: bool,
592 pub unk9: bool,
593 pub fur: bool,
595 pub unk11: u17,
596 pub fur_shells: bool,
598 pub unk: u4,
599}
600
601#[bitsize(32)]
602#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
603#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
604#[br(map = u32::into)]
605#[bw(map = |&x| u32::from(x))]
606pub struct MaterialRenderFlags {
607 pub unk1: bool,
608 pub unk2: bool,
609 pub unk3: bool,
610 pub unk4: bool,
611 pub unk5: bool,
612 pub unk6: bool,
613 pub speff_zpre: bool, pub unk8: bool,
617 pub unk9: bool,
618 pub unk10: bool, pub unk11: bool,
620 pub specular: bool, pub unk13: bool, pub unk14: bool, pub unk15: bool, pub unk16: bool, pub unk17: bool,
627 pub unk18: bool,
628 pub unk19: bool,
629 pub unk20: bool,
630 pub speff_ope: bool,
633 pub unk22: bool,
634 pub unk23: bool,
635 pub unk24: bool,
636 pub unk25: bool,
637 pub unk26: bool,
638 pub unk: u6,
639}
640
641#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
643#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
644pub struct StateFlags {
645 pub depth_write_mode: u8, pub blend_mode: BlendMode,
647 pub cull_mode: CullMode,
648 pub unk4: u8, pub stencil_value: StencilValue,
650 pub stencil_mode: StencilMode,
651 pub depth_func: DepthFunc,
652 pub color_write_mode: ColorWriteMode,
653}
654
655#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
657#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
658#[brw(repr(u8))]
659pub enum ColorWriteMode {
660 Unk0 = 0, Unk1 = 1, Unk2 = 2, Unk3 = 3, Unk5 = 5, Unk6 = 6, Unk9 = 9, Unk10 = 10, Unk11 = 11, Unk12 = 12, }
671
672#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
682#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
683#[brw(repr(u8))]
684pub enum BlendMode {
685 Disabled = 0,
686 Blend = 1,
687 Unk2 = 2,
688 Multiply = 3,
689 MultiplyInverted = 4,
690 Add = 5,
691 Disabled2 = 6,
692}
693
694#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
696#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
697#[brw(repr(u8))]
698pub enum StencilValue {
699 Unk0 = 0,
701 Unk1 = 1,
702 Unk4 = 4,
704 Unk5 = 5,
705 Unk8 = 8,
706 Unk9 = 9,
707 Unk12 = 12,
708 Unk16 = 16,
710 Unk20 = 20,
711 Unk33 = 33,
713 Unk37 = 37,
714 Unk41 = 41,
715 Unk49 = 49,
716 Unk97 = 97,
717 Unk105 = 105,
718 Unk128 = 128, }
720
721#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
723#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
724#[brw(repr(u8))]
725pub enum StencilMode {
726 Unk0 = 0, Unk1 = 1, Unk2 = 2, Unk6 = 6, Unk7 = 7, Unk8 = 8, Unk9 = 9, Unk12 = 12, Unk13 = 13, }
737
738#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
739#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
740#[brw(repr(u8))]
741pub enum DepthFunc {
742 Disabled = 0,
743 LessEqual = 1,
744 Equal = 3,
745}
746
747#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
748#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
749#[brw(repr(u8))]
750pub enum CullMode {
751 Back = 0,
752 Front = 1,
753 Disabled = 2,
754 Unk3 = 3, }
756
757#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
759#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
760pub struct MaterialTechnique {
761 pub technique_index: u32,
764 pub pass_type: RenderPassType,
765 pub material_buffer_index: u16,
766 pub flags: u32, }
768
769#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
776#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy, Hash)]
777#[brw(repr(u16))]
778pub enum RenderPassType {
779 Unk0 = 0, Unk1 = 1, Unk6 = 6, Unk7 = 7, Unk9 = 9, }
785
786#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
787#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
788pub struct Texture {
789 pub texture_index: u16,
792 pub sampler_index: u16,
794 pub sampler_index2: u16,
797 pub unk3: u16, }
799
800#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
801#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
802#[br(import_raw(base_offset: u64))]
803pub struct MaterialUnk5 {
804 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
805 #[xc3(offset(u32))]
806 pub unk1: Option<MaterialUnk5Inner>,
807}
808
809#[binread]
810#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
811#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
812#[br(stream = r)]
813#[xc3(base_offset)]
814pub struct MaterialUnk5Inner {
815 #[br(temp, try_calc = r.stream_position())]
816 base_offset: u64,
817
818 pub unk1: u32,
819
820 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
822 #[xc3(count_offset(u32, u32))]
823 pub unk2: Vec<[f32; 6]>,
824}
825
826#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
827#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
828#[br(import_raw(base_offset: u64))]
829pub struct MaterialUnk6 {
830 #[br(parse_with = parse_count32_offset32)]
831 #[br(args { offset: base_offset, inner: base_offset })]
832 #[xc3(count_offset(u32, u32))]
833 pub items: Vec<MaterialUnk6Item>,
834}
835
836#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
837#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
838#[br(import_raw(base_offset: u64))]
839pub struct MaterialUnk6Item {
840 pub unk1: u32,
841 pub material_index: u32,
842 pub unk3: u32,
843
844 #[br(parse_with = parse_count32_offset32)]
845 #[br(args { offset: base_offset, inner: base_offset })]
846 #[xc3(count_offset(u32, u32))]
847 pub unk4: Vec<MaterialUnk6ItemUnk4>,
848}
849
850#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
851#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
852#[br(import_raw(base_offset: u64))]
853pub struct MaterialUnk6ItemUnk4 {
854 pub unk1: u32,
855
856 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
857 #[xc3(count_offset(u32, u32))]
858 pub unk2: Vec<[f32; 3]>,
859}
860
861#[binread]
866#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
867#[derive(Debug, Xc3Write, PartialEq, Clone)]
868#[br(stream = r)]
869#[xc3(base_offset)]
870pub struct ModelsV112 {
871 #[br(temp, try_calc = r.stream_position())]
872 base_offset: u64,
873
874 pub models_flags: ModelsFlags,
875
876 pub max_xyz: [f32; 3],
878 pub min_xyz: [f32; 3],
880
881 #[br(temp, restore_position)]
882 models_offset: u32,
883
884 #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
885 #[xc3(offset_count(u32, u32))]
886 pub models: Vec<ModelV112>,
887
888 pub unk2: u32,
889
890 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
891 #[xc3(offset(u32))]
892 pub skinning: Option<Skinning>,
893
894 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
895 #[xc3(offset(u32))]
896 pub model_unk11: Option<ModelUnk11>,
897
898 pub unks3_1: [u32; 13],
899
900 #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
902 #[xc3(offset_count(u32, u32), align(16))]
903 pub ext_meshes: Vec<ExtMesh>,
904
905 pub unks3_2: [u32; 2],
908
909 #[br(parse_with = parse_opt_ptr32)]
910 #[br(args { offset: base_offset, inner: base_offset })]
911 #[xc3(offset(u32))]
912 pub model_unk8: Option<ModelUnk8>,
913
914 pub unk3_3: u32,
915
916 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
917 #[xc3(offset(u32))]
918 pub model_unk7: Option<ModelUnk7>,
919
920 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
922 #[xc3(offset(u32), align(16))]
923 pub morph_controllers: Option<MorphControllers>,
924
925 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
927 #[xc3(offset(u32), align(16))]
928 pub model_unk1: Option<ModelUnk1>,
929
930 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
931 #[xc3(offset(u32))]
932 pub model_unk3: Option<ModelUnk3>,
933
934 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
936 #[xc3(offset(u32), align(8))]
937 pub lod_data: Option<LodData>,
938
939 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
942 #[xc3(offset(u32), align(4))]
943 pub alpha_table: Option<AlphaTable>,
944
945 pub unk_field2: u32,
946
947 #[br(parse_with = parse_opt_ptr32)]
948 #[br(args { offset: base_offset, inner: base_offset})]
949 #[xc3(offset(u32))]
950 pub model_unk9: Option<ModelUnk9>,
951
952 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
954 #[xc3(offset(u32))]
955 pub model_unk12: Option<ModelUnk12>,
956
957 #[br(args { size: models_offset, base_offset})]
962 pub extra: ModelsExtraData,
963}
964
965#[binread]
966#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
967#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
968#[br(stream = r)]
969#[xc3(base_offset)]
970pub struct ModelsV111 {
971 #[br(temp, try_calc = r.stream_position())]
972 base_offset: u64,
973
974 pub max_xyz: [f32; 3],
976 pub min_xyz: [f32; 3],
978
979 #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
980 #[xc3(offset_count(u32, u32))]
981 pub models: Vec<ModelV111>,
982
983 pub unk2: u32,
984
985 pub model_unk16: u32,
986
987 pub model_unk11: u32,
988
989 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
990 #[xc3(offset(u32))]
991 pub skinning: Option<Skinning>,
992
993 pub unks3_1: [u32; 12],
994
995 pub ext_meshes: [u32; 2],
997
998 pub unks3_2: [u32; 2],
1001
1002 pub model_unk8: u32,
1003
1004 pub unk3_3: u32,
1005
1006 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1007 #[xc3(offset(u32))]
1008 pub model_unk7: Option<ModelUnk7>,
1009
1010 pub morph_controllers: u32,
1012
1013 pub model_unk1: u32,
1014
1015 pub model_unk12: u32,
1016
1017 pub lod_data: u32,
1018
1019 pub alpha_table: u32,
1020
1021 pub unk_field2: u32,
1022
1023 pub model_unk9: u32,
1024
1025 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1027 #[xc3(offset(u32))]
1028 pub model_unk3: Option<ModelUnk3>,
1029
1030 pub model_unk13: u32,
1032 pub model_unk14: u32,
1033 pub model_unk15: u32,
1034}
1035
1036#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1039#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1040#[br(import { size: u32, base_offset: u64 })]
1041pub enum ModelsExtraData {
1042 #[br(pre_assert(size == 160))]
1043 Unk1,
1044
1045 #[br(pre_assert(size == 164))]
1046 Unk2(#[br(args_raw(base_offset))] ModelsExtraDataUnk2),
1047
1048 #[br(pre_assert(size == 168))]
1049 Unk3(#[br(args_raw(base_offset))] ModelsExtraDataUnk3),
1050
1051 #[br(pre_assert(size == 200))]
1052 Unk4(#[br(args_raw(base_offset))] ModelsExtraDataUnk4),
1053
1054 #[br(pre_assert(size == 204))]
1055 Unk5(#[br(args_raw(base_offset))] ModelsExtraDataUnk5),
1056}
1057
1058#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1061#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1062#[br(import_raw(base_offset: u64))]
1063pub struct ModelsExtraDataUnk2 {
1064 #[br(parse_with = parse_opt_ptr32)]
1065 #[br(args { offset: base_offset, inner: base_offset })]
1066 #[xc3(offset(u32))]
1067 pub model_unk10: Option<ModelUnk10>,
1068}
1069
1070#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1072#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1073#[br(import_raw(base_offset: u64))]
1074pub struct ModelsExtraDataUnk3 {
1075 #[br(parse_with = parse_opt_ptr32)]
1076 #[br(args { offset: base_offset, inner: base_offset })]
1077 #[xc3(offset(u32))]
1078 pub model_unk10: Option<ModelUnk10>,
1079
1080 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1081 #[xc3(offset(u32))]
1082 pub model_unk5: Option<ModelUnk5>,
1083}
1084
1085#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1087#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1088#[br(import_raw(base_offset: u64))]
1089pub struct ModelsExtraDataUnk4 {
1090 #[br(parse_with = parse_opt_ptr32)]
1091 #[br(args { offset: base_offset, inner: base_offset })]
1092 #[xc3(offset(u32))]
1093 pub model_unk10: Option<ModelUnk10>,
1094
1095 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1096 #[xc3(offset(u32))]
1097 pub model_unk5: Option<ModelUnk5>,
1098
1099 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1100 #[xc3(offset(u32))]
1101 pub model_unk6: Option<ModelUnk6>,
1102
1103 pub unk: Option<[u32; 7]>,
1105}
1106
1107#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1109#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1110#[br(import_raw(base_offset: u64))]
1111pub struct ModelsExtraDataUnk5 {
1112 #[br(parse_with = parse_opt_ptr32)]
1113 #[br(args { offset: base_offset, inner: base_offset })]
1114 #[xc3(offset(u32))]
1115 pub model_unk10: Option<ModelUnk10>,
1116
1117 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1118 #[xc3(offset(u32))]
1119 pub model_unk5: Option<ModelUnk5>,
1120
1121 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1122 #[xc3(offset(u32))]
1123 pub model_unk6: Option<ModelUnk6>,
1124
1125 pub unk: Option<[u32; 8]>,
1127}
1128
1129#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1133#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1134#[br(import_raw(base_offset: u64))]
1135pub struct ModelV111 {
1136 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1137 #[xc3(offset_count(u32, u32))]
1138 pub meshes: Vec<MeshV111>,
1139
1140 pub unk1: u32, pub max_xyz: [f32; 3],
1146 pub min_xyz: [f32; 3],
1148 pub bounding_radius: f32,
1150 pub unks1: [u32; 3], pub unk2: (u16, u16), pub unks: [u32; 3],
1154}
1155
1156#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1160#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1161#[br(import_raw(base_offset: u64))]
1162pub struct ModelV112 {
1163 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1164 #[xc3(offset_count(u32, u32))]
1165 pub meshes: Vec<MeshV112>,
1166
1167 pub unk1: u32, pub max_xyz: [f32; 3],
1173 pub min_xyz: [f32; 3],
1175 pub bounding_radius: f32,
1177 pub unks1: [u32; 3], pub unk2: (u16, u16), pub unks: [u32; 3],
1181}
1182
1183#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1186#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1187pub struct MeshV111 {
1188 pub flags1: u32,
1189 pub flags2: MeshRenderFlags2,
1190 pub vertex_buffer_index: u16,
1193 pub index_buffer_index: u16,
1196 pub index_buffer_index2: u16,
1200 pub material_index: u16,
1202 pub unk2: u32, pub unk3: u16, pub ext_mesh_index: u16,
1207 pub unk4: u32, pub unk5: u16, pub lod_item_index: u8,
1211 pub unk_mesh_index2: u8, pub alpha_table_index: u16,
1214 pub unk6: u16, pub base_mesh_index: i32,
1218 pub unk8: u32, pub unk9: u32, pub unk10: [u32; 4],
1221}
1222
1223#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1225#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1226pub struct MeshV112 {
1227 pub flags1: u32, pub flags2: MeshRenderFlags2,
1229 pub vertex_buffer_index: u16,
1232 pub index_buffer_index: u16,
1235 pub index_buffer_index2: u16,
1239 pub material_index: u16,
1241 pub unk2: u32, pub unk3: u16, pub ext_mesh_index: u16,
1246 pub unk4: u32, pub unk5: u16, pub lod_item_index: u8,
1250 pub unk_mesh_index2: u8, pub alpha_table_index: u16,
1253 pub unk6: u16, pub base_mesh_index: i32,
1257 pub unk8: u32, pub unk9: u32, }
1260
1261#[bitsize(32)]
1264#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1265#[derive(DebugBits, TryFromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
1266#[br(try_map = |x: u32| x.try_into().map_err(|e| format!("{e:?}")))]
1267#[bw(map = |&x| u32::from(x))]
1268pub struct MeshRenderFlags2 {
1269 pub render_pass: MeshRenderPass,
1271 pub unk5: u28,
1272}
1273
1274#[bitsize(4)]
1278#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1279#[derive(Debug, TryFromBits, PartialEq, Clone, Copy)]
1280pub enum MeshRenderPass {
1281 Unk0 = 0,
1283 Unk1 = 1,
1285 Unk2 = 2,
1287 Unk4 = 4, Unk8 = 8,
1290}
1291
1292#[bitsize(32)]
1294#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1295#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
1296#[br(map = u32::into)]
1297#[bw(map = |&x| u32::from(x))]
1298pub struct ModelsFlags {
1299 pub unk1: bool,
1300 pub has_model_unk8: bool,
1301 pub unk3: bool,
1302 pub unk4: bool,
1303 pub unk5: bool,
1304 pub unk6: bool,
1305 pub has_model_unk7: bool,
1306 pub unk8: bool,
1307 pub unk9: bool,
1308 pub unk10: bool,
1309 pub has_morph_controllers: bool,
1310 pub has_model_unk1: bool,
1311 pub has_model_unk3: bool,
1312 pub unk14: bool,
1313 pub unk15: bool,
1314 pub has_skinning: bool,
1315 pub unk17: bool,
1316 pub has_lod_data: bool,
1317 pub has_alpha_table: bool,
1318 pub unk20: bool,
1319 pub unk21: bool,
1320 pub unk22: bool,
1321 pub unk23: bool,
1322 pub unk24: bool,
1323 pub unk25: bool,
1324 pub unk26: bool,
1325 pub unk27: bool,
1326 pub unk28: bool,
1327 pub unk29: bool,
1328 pub unk30: bool,
1329 pub unk31: bool,
1330 pub unk32: bool,
1331}
1332
1333#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1335#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1336#[br(import_raw(base_offset: u64))]
1337pub struct ExtMesh {
1338 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1339 #[xc3(offset(u32))]
1340 pub name1: String,
1341
1342 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1344 #[xc3(offset(u32))]
1345 pub name2: String,
1346
1347 pub flags: ExtMeshFlags,
1348 pub unk2: u16,
1349 pub unk3: u32,
1350}
1351
1352#[bitsize(16)]
1353#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1354#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
1355#[br(map = u16::into)]
1356#[bw(map = |&x| u16::from(x))]
1357pub struct ExtMeshFlags {
1358 pub unk1: bool, pub unk2: bool, pub unk3: bool, pub start_hidden: bool,
1363 pub unk5: bool,
1364 pub unk6: bool, pub unk: u10, }
1367
1368#[binread]
1369#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1370#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1371#[br(stream = r)]
1372#[xc3(base_offset)]
1373pub struct MorphControllers {
1374 #[br(temp, try_calc = r.stream_position())]
1375 base_offset: u64,
1376
1377 #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
1379 #[xc3(offset_count(u32, u32))]
1380 pub controllers: Vec<MorphController>,
1381
1382 pub unk1: u32,
1383
1384 pub unk: [u32; 3],
1386}
1387
1388#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1389#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1390#[br(import_raw(base_offset: u64))]
1391pub struct MorphController {
1392 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1393 #[xc3(offset(u32))]
1394 pub name1: String,
1395
1396 #[br(parse_with = parse_string_opt_ptr32, offset = base_offset)]
1398 #[xc3(offset(u32))]
1399 pub name2: Option<String>,
1400
1401 pub unk1: u16, pub unk2: u16, pub unk3: u16, pub unk4: u16, pub unk: [u32; 3],
1408}
1409
1410#[binread]
1411#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1412#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1413#[br(stream = r)]
1414#[xc3(base_offset)]
1415pub struct ModelUnk3 {
1416 #[br(temp, try_calc = r.stream_position())]
1417 base_offset: u64,
1418
1419 #[br(parse_with = parse_count32_offset32, args { offset: base_offset, inner: base_offset })]
1420 #[xc3(count_offset(u32, u32))]
1421 pub items: Vec<ModelUnk3Item>,
1422
1423 pub unk: [u32; 4],
1425}
1426
1427#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1428#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
1429#[br(import_raw(base_offset: u64))]
1430pub struct ModelUnk3Item {
1431 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1433 #[xc3(offset(u32))]
1434 pub name: String,
1435 pub unk1: u32, pub unk2: u32,
1437
1438 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1439 #[xc3(offset_count(u32, u32))]
1440 pub unk3: Vec<u16>,
1441}
1442
1443#[binread]
1444#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1445#[derive(Debug, Xc3Write, PartialEq, Clone)]
1446#[br(stream = r)]
1447#[xc3(base_offset)]
1448pub struct Unk8 {
1449 #[br(temp, try_calc = r.stream_position())]
1450 base_offset: u64,
1451
1452 pub unk1: u32,
1453
1454 #[br(parse_with = parse_count32_offset32)]
1455 #[br(args { offset: base_offset, inner: base_offset })]
1456 #[xc3(count_offset(u32, u32))]
1457 pub unk2: Vec<Unk8Item>,
1458
1459 #[br(parse_with = parse_ptr32)]
1460 #[br(args { offset: base_offset, inner: args! { count: unk2.len() } })]
1461 #[xc3(offset(u32), align(16))]
1462 pub unk3: Vec<[[f32; 4]; 4]>,
1463
1464 pub unk: [u32; 4],
1466}
1467
1468#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1469#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1470#[br(import_raw(base_offset: u64))]
1471pub struct Unk8Item {
1472 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1473 #[xc3(offset(u32))]
1474 pub name: String,
1475 pub unk1: u32,
1476 pub unk2: [[f32; 4]; 4],
1477 pub unk3: u32,
1478}
1479
1480#[binread]
1482#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1483#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1484#[br(stream = r)]
1485#[xc3(base_offset)]
1486pub struct AlphaTable {
1487 #[br(temp, try_calc = r.stream_position())]
1488 base_offset: u64,
1489
1490 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1494 #[xc3(offset_count(u32, u32))]
1495 pub items: Vec<(u16, u16)>,
1496
1497 pub unks: [u32; 4],
1499}
1500
1501#[binread]
1502#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1503#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1504#[br(stream = r)]
1505#[xc3(base_offset)]
1506pub struct ModelUnk5 {
1507 #[br(temp, try_calc = r.stream_position())]
1508 base_offset: u64,
1509
1510 #[br(parse_with = parse_count32_offset32)]
1512 #[br(args { offset: base_offset, inner: base_offset })]
1513 #[xc3(count_offset(u32, u32))]
1514 pub items: Vec<StringOffset32>,
1515
1516 pub unks: [u32; 4],
1518}
1519
1520#[binread]
1521#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1522#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1523#[br(stream = r)]
1524#[xc3(base_offset)]
1525pub struct ModelUnk6 {
1526 #[br(temp, try_calc = r.stream_position())]
1527 base_offset: u64,
1528
1529 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
1531 #[xc3(count_offset(u32, u32))]
1532 pub items: Vec<[u32; 2]>,
1533
1534 pub unks: [u32; 4],
1536}
1537
1538#[binread]
1539#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1540#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1541#[br(stream = r)]
1542#[xc3(base_offset)]
1543pub struct ModelUnk7 {
1544 #[br(temp, try_calc = r.stream_position())]
1545 base_offset: u64,
1546
1547 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
1549 #[xc3(count_offset(u32, u32))]
1550 pub items: Vec<[f32; 9]>,
1551
1552 pub unks: [u32; 4],
1554}
1555
1556#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1557#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1558#[br(import_raw(base_offset: u64))]
1559pub struct ModelUnk8 {
1560 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1562 #[xc3(offset_count(u32, u32))]
1563 pub unk1: Vec<[u32; 2]>,
1564
1565 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1567 #[xc3(offset_count(u32, u32))]
1568 pub unk2: Vec<[f32; 4]>,
1569
1570 pub unks: [u32; 2],
1572}
1573
1574#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1575#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1576#[br(import_raw(base_offset: u64))]
1577pub struct ModelUnk9 {
1578 pub unk1: u32,
1582
1583 #[br(args { unk1, base_offset})]
1584 pub inner: ModelUnk9Inner,
1585}
1586
1587#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1588#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1589#[br(import { unk1: u32, base_offset: u64 })]
1590pub enum ModelUnk9Inner {
1591 #[br(pre_assert(unk1 != 10000))]
1593 Unk0(ModelUnk9InnerUnk0),
1594
1595 #[br(pre_assert(unk1 == 10000))]
1596 Unk1(#[br(args_raw(base_offset))] ModelUnk9InnerUnk1),
1597}
1598
1599#[binread]
1600#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1601#[derive(Debug, Xc3Write, PartialEq, Clone)]
1602#[br(stream = r)]
1603#[xc3(base_offset)]
1604pub struct ModelUnk9InnerUnk0 {
1605 #[br(temp, try_calc = r.stream_position().map(|p| p - 4))]
1607 base_offset: u64,
1608
1609 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1610 #[xc3(offset_count(u32, u32))]
1611 pub items1: Vec<(u16, u16)>,
1612
1613 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1614 #[xc3(offset_count(u32, u32))]
1615 pub items2: Vec<(u16, u16)>,
1616
1617 pub unk: [u32; 4],
1619}
1620
1621#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1622#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1623#[br(import_raw(base_offset: u64))]
1624pub struct ModelUnk9InnerUnk1 {
1625 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1627 #[xc3(offset_count(u32, u32))]
1628 pub items: Vec<ModelUnk9Buffer>,
1629
1630 #[br(parse_with = parse_ptr32)]
1631 #[br(args { offset: base_offset, inner: args! { count: model_unk9_buffer_length(&items) } })]
1632 #[xc3(offset(u32))]
1633 pub buffer: Vec<u8>,
1634
1635 pub unk2: u32,
1637
1638 pub unk: [u32; 3],
1640}
1641
1642#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1643#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1644pub struct ModelUnk9Buffer {
1645 pub offset: u32,
1647 pub count: u32,
1648}
1649
1650#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1651#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1652#[br(import_raw(base_offset: u64))]
1653pub struct ModelUnk10 {
1654 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1655 #[xc3(offset_count(u32, u32))]
1656 pub unk1: Vec<u32>,
1657}
1658
1659#[binread]
1660#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1661#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1662#[br(stream = r)]
1663#[xc3(base_offset)]
1664pub struct ModelUnk11 {
1665 #[br(temp, try_calc = r.stream_position())]
1666 base_offset: u64,
1667
1668 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
1669 #[xc3(count_offset(u32, u32))]
1670 pub unk1: Vec<[u32; 6]>,
1671
1672 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
1673 #[xc3(count_offset(u32, u32))]
1674 pub unk2: Vec<[u32; 2]>,
1675
1676 pub unks: [u32; 4],
1678}
1679
1680#[binread]
1681#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1682#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1683#[br(stream = r)]
1684#[xc3(base_offset)]
1685pub struct ModelUnk12 {
1686 #[br(temp, try_calc = r.stream_position())]
1687 base_offset: u64,
1688
1689 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1690 #[xc3(offset_count(u32, u32))]
1691 pub items: Vec<ModelUnk12Item>,
1692
1693 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1694 #[xc3(offset_count(u32, u32))]
1695 pub indices: Vec<u32>,
1696
1697 pub unk2: u32,
1698
1699 pub unk: [u16; 22],
1701}
1702
1703#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1704#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1705pub struct ModelUnk12Item {
1706 pub unk1: [f32; 4],
1707 pub unk2: [f32; 4],
1708 pub unk3: [f32; 4],
1709 pub unk4: [f32; 4],
1710}
1711
1712#[binread]
1714#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1715#[derive(Debug, Xc3Write, PartialEq, Clone)]
1716#[br(stream = r)]
1717#[xc3(base_offset)]
1718pub struct ModelUnk1 {
1719 #[br(temp, try_calc = r.stream_position())]
1720 base_offset: u64,
1721
1722 #[br(parse_with = parse_offset32_count32)]
1725 #[br(args { offset: base_offset, inner: base_offset })]
1726 #[xc3(offset_count(u32, u32), align(4))]
1727 pub items1: Vec<ModelUnk1Item1>,
1728
1729 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1730 #[xc3(offset_count(u32, u32))]
1731 pub items2: Vec<ModelUnk1Item2>,
1732
1733 #[br(parse_with = parse_ptr32)]
1736 #[br(args { offset: base_offset, inner: args! { count: items1.len() }})]
1737 #[xc3(offset(u32))]
1738 pub items3: Vec<f32>,
1739
1740 pub unk1: u32, #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1743 #[xc3(offset_count(u32, u32))]
1744 pub items4: Vec<[u16; 10]>,
1745
1746 pub unk4: u32,
1748 pub unk5: u32,
1749 #[br(if(unk4 != 0 || unk5 != 0))]
1752 #[br(args_raw(base_offset))]
1753 pub extra: Option<ModelUnk1Extra>,
1754}
1755
1756#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1757#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1758#[br(import_raw(base_offset: u64))]
1759pub struct ModelUnk1Extra {
1760 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
1761 #[xc3(offset(u32))]
1762 pub unk_inner: Option<ModelUnk1Inner>,
1763
1764 pub unk: [u32; 4],
1766}
1767
1768#[binread]
1770#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1771#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1772#[br(stream = r)]
1773#[xc3(base_offset)]
1774pub struct ModelUnk1Inner {
1775 #[br(temp, try_calc = r.stream_position())]
1776 base_offset: u64,
1777
1778 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1781 #[xc3(offset_count(u32, u32))]
1782 pub items1: Vec<(u16, u16)>,
1783
1784 #[br(parse_with = parse_ptr32)]
1786 #[br(args {
1787 offset: base_offset,
1788 inner: args! { count: items1.iter().map(|(i, j)| (*i + *j) as usize).max().unwrap_or_default() }
1789 })]
1790 #[xc3(offset(u32))]
1791 pub items2: Vec<u16>,
1792
1793 pub unks: [u32; 5],
1795}
1796
1797#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1798#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1799#[br(import_raw(base_offset: u64))]
1800pub struct ModelUnk1Item1 {
1801 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1802 #[xc3(offset(u32))]
1803 pub name: String,
1804 pub unk: [u32; 3],
1806}
1807
1808#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1809#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1810pub struct ModelUnk1Item2 {
1811 pub unk1: u16,
1812 pub unk2: u16,
1813 pub unk3: u32,
1814 pub unk4: u32,
1815 pub unk5: u32,
1816 pub unk6: u32,
1817}
1818
1819#[binread]
1820#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1821#[derive(Debug, Xc3Write, PartialEq, Clone)]
1822#[br(stream = r)]
1823#[xc3(base_offset)]
1824pub struct LodData {
1825 #[br(temp, try_calc = r.stream_position())]
1826 base_offset: u64,
1827
1828 pub unk1: u32, #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1832 #[xc3(offset_count(u32, u32), align(16))]
1833 pub items: Vec<LodItem>,
1834
1835 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
1836 #[xc3(offset_count(u32, u32))]
1837 pub groups: Vec<LodGroup>,
1838
1839 pub unks: [u32; 4],
1840}
1841
1842#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1844#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1845pub struct LodItem {
1846 pub unk1: [u32; 4], pub unk2: f32, pub unk3: u8, pub index: u8, pub unk5: u8, pub unk6: u8, pub unk7: [u32; 2], }
1854
1855#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1856#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1857pub struct LodGroup {
1858 pub base_lod_index: u16,
1860 pub lod_count: u16,
1862}
1863
1864#[binread]
1866#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1867#[derive(Debug, Xc3Write, PartialEq, Clone)]
1868#[br(stream = r)]
1869#[xc3(base_offset)]
1870pub struct PackedTextures {
1871 #[br(temp, try_calc = r.stream_position())]
1872 base_offset: u64,
1873
1874 #[br(parse_with = parse_count32_offset32, args { offset: base_offset, inner: base_offset })]
1875 #[xc3(count_offset(u32, u32))]
1876 pub textures: Vec<PackedTexture>,
1877
1878 pub unk2: u32,
1879
1880 #[xc3(shared_offset)]
1881 pub strings_offset: u32,
1882}
1883
1884#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1886#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1887#[br(import_raw(base_offset: u64))]
1888pub struct PackedTexture {
1889 pub usage: TextureUsage,
1890
1891 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
1892 #[xc3(count_offset(u32, u32), align(4096))]
1893 pub mibl_data: Vec<u8>,
1894
1895 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1896 #[xc3(offset(u32))]
1897 pub name: String,
1898}
1899
1900#[binread]
1902#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1903#[derive(Debug, Xc3Write, PartialEq, Clone)]
1904#[br(stream = r)]
1905#[xc3(base_offset)]
1906pub struct PackedExternalTextures<U>
1907where
1908 U: Xc3Write + 'static,
1909 for<'a> U: BinRead<Args<'a> = ()>,
1910 for<'a> U::Offsets<'a>: Xc3WriteOffsets<Args = ()>,
1911{
1912 #[br(temp, try_calc = r.stream_position())]
1913 base_offset: u64,
1914
1915 #[br(parse_with = parse_count32_offset32, args { offset: base_offset, inner: base_offset })]
1917 #[xc3(count_offset(u32, u32), align(2))]
1918 pub textures: Vec<PackedExternalTexture<U>>,
1919
1920 pub unk2: u32, #[xc3(shared_offset)]
1923 pub strings_offset: u32,
1924}
1925
1926#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1927#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
1928#[br(import_raw(base_offset: u64))]
1929pub struct PackedExternalTexture<U>
1930where
1931 U: Xc3Write + 'static,
1932 for<'a> U: BinRead<Args<'a> = ()>,
1933 for<'a> U::Offsets<'a>: Xc3WriteOffsets<Args = ()>,
1934{
1935 pub usage: U,
1936
1937 pub length: u32,
1939 pub offset: u32,
1941
1942 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
1943 #[xc3(offset(u32))]
1944 pub name: String,
1945}
1946
1947#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1954#[derive(Debug, BinRead, BinWrite, Clone, Copy, PartialEq, Eq, Hash)]
1955#[brw(repr(u32))]
1956pub enum TextureUsage {
1957 Unk0 = 0,
1958 Temp = 1048576,
1960 Unk6 = 1074790400,
1961 Nrm = 1179648,
1962 Unk13 = 131072,
1963 WavePlus = 136314882,
1964 Col = 2097152,
1965 Unk8 = 2162689,
1966 Alp = 2228224,
1967 Unk = 268435456,
1968 Unk21 = 269615104,
1969 Alp2 = 269484032,
1970 Col2 = 270532608,
1971 Unk11 = 270663680,
1972 Unk9 = 272629760,
1973 Alp3 = 273678336,
1974 Nrm2 = 273809408,
1975 Col3 = 274726912,
1976 Unk3 = 274857984,
1977 Unk2 = 275775488,
1978 Unk20 = 287309824,
1979 Unk17 = 3276800,
1980 F01 = 403701762, Unk4 = 4194304,
1982 Unk7 = 536870912,
1983 Unk15 = 537001984,
1984 Temp2 = 537919488,
1986 Unk14 = 538050560,
1987 Col4 = 538968064,
1988 Alp4 = 539099136,
1989 Unk12 = 540147712,
1990 Unk18 = 65537,
1991 Unk19 = 805306368,
1992 Unk5 = 807403520,
1993 Unk10 = 807534592,
1994 VolTex = 811597824,
1995 Unk16 = 811728896,
1996
1997 Unk22 = 6291456,
1999 Unk23 = 5242880,
2000 Unk24 = 69206016,
2001 Unk25 = 7340032,
2002 Unk26 = 3145728,
2003 Unk27 = 73400320,
2004 Unk28 = 35651584,
2005 Unk29 = 34734080,
2006 Unk30 = 34603008,
2007}
2008
2009#[binread]
2014#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2015#[derive(Debug, Xc3Write, PartialEq, Clone)]
2016#[br(stream = r)]
2017#[xc3(base_offset)]
2018pub struct Skinning {
2019 #[br(temp, try_calc = r.stream_position())]
2020 base_offset: u64,
2021
2022 pub render_bone_count: u32,
2023 pub bone_count: u32,
2024
2025 #[br(temp, restore_position)]
2027 bones_offset: u32,
2028
2029 #[br(parse_with = parse_ptr32)]
2033 #[br(args {
2034 offset: base_offset,
2035 inner: args! { count: bone_count as usize, inner: base_offset }
2036 })]
2037 #[xc3(offset(u32))]
2038 pub bones: Vec<Bone>,
2039
2040 #[br(parse_with = parse_ptr32)]
2042 #[br(args { offset: base_offset, inner: args! { count: bone_count as usize } })]
2043 #[xc3(offset(u32), align(16))]
2044 pub inverse_bind_transforms: Vec<[[f32; 4]; 4]>,
2045
2046 #[br(parse_with = parse_opt_ptr32)]
2048 #[br(args { offset: base_offset, inner: args! { count: count_constraints(&bones) } })]
2049 #[xc3(offset(u32))]
2050 pub constraints: Option<Vec<BoneConstraint>>,
2051
2052 #[br(parse_with = parse_opt_ptr32)]
2053 #[br(args { offset: base_offset, inner: args! { count: count_bounds(&bones) } })]
2054 #[xc3(offset(u32))]
2055 pub bounds: Option<Vec<BoneBounds>>,
2056
2057 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2059 #[xc3(count_offset(u32, u32))]
2060 pub bone_indices: Vec<u16>,
2061
2062 #[br(if(constraints.is_some()))]
2065 #[br(args_raw(base_offset))]
2066 pub unk_offset4: Option<SkinningUnkBones>,
2067
2068 #[br(if(bounds.is_some()))]
2069 #[br(args_raw(base_offset))]
2070 pub unk_offset5: Option<SkinningUnk5>,
2071
2072 #[br(if(!bone_indices.is_empty()))]
2075 #[br(args_raw(base_offset))]
2076 pub as_bone_data: Option<SkinningAsBoneData>,
2077
2078 #[br(if(bones_offset == 52))]
2081 pub unk1: Option<[u32; 2]>,
2082
2083 #[br(if(bones_offset == 60))]
2084 pub unk2: Option<[u32; 4]>,
2085}
2086
2087#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2088#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2089#[br(import_raw(base_offset: u64))]
2090pub struct SkinningUnkBones {
2091 #[br(parse_with = parse_opt_ptr32)]
2092 #[br(args { offset: base_offset, inner: base_offset })]
2093 #[xc3(offset(u32))]
2094 pub unk_offset4: Option<UnkBones>,
2095}
2096
2097#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2098#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2099#[br(import_raw(base_offset: u64))]
2100pub struct SkinningUnk5 {
2101 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
2102 #[xc3(offset(u32))]
2103 pub unk_offset5: Option<SkeletonUnk5>,
2104}
2105
2106#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2107#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2108#[br(import_raw(base_offset: u64))]
2109pub struct SkinningAsBoneData {
2110 #[br(parse_with = parse_opt_ptr32, args { offset: base_offset, inner: base_offset })]
2112 #[xc3(offset(u32))]
2113 pub as_bone_data: Option<AsBoneData>,
2114}
2115
2116#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2117#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2118pub struct BoneConstraint {
2119 pub fixed_offset: [f32; 3],
2120 pub max_distance: f32,
2121}
2122
2123#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2124#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2125pub struct BoneBounds {
2126 pub center: [f32; 4],
2127 pub size: [f32; 4],
2128}
2129
2130#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2131#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2132#[br(import_raw(base_offset: u64))]
2133pub struct Bone {
2134 #[br(parse_with = parse_string_ptr32, offset = base_offset)]
2135 #[xc3(offset(u32))]
2136 pub name: String,
2137 pub bounds_radius: f32,
2138 pub flags: BoneFlags,
2139 pub constraint_index: u8,
2142 pub parent_index: u8,
2145 pub bounds_index: u32,
2148 pub unk: [u32; 2],
2150}
2151
2152#[bitsize(16)]
2153#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2154#[derive(DebugBits, FromBits, BinRead, BinWrite, PartialEq, Clone, Copy)]
2155#[br(map = u16::into)]
2156#[bw(map = |&x| u16::from(x))]
2157pub struct BoneFlags {
2158 pub fixed_offset_constraint: bool,
2159 pub bounds_offset: bool,
2160 pub distance_constraint: bool,
2161 pub no_camera_overlap: bool,
2162 pub unk: u12,
2163}
2164
2165#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2166#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2167#[br(import_raw(base_offset: u64))]
2168pub struct UnkBones {
2169 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
2170 #[xc3(offset_count(u32, u32))]
2171 pub bones: Vec<UnkBone>,
2172
2173 #[br(parse_with = parse_ptr32)]
2174 #[br(args { offset: base_offset, inner: args! { count: bones.len() }})]
2175 #[xc3(offset(u32), align(16))]
2176 pub unk_offset: Vec<[[f32; 4]; 4]>,
2177 }
2179
2180#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2181#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2182pub struct UnkBone {
2183 pub unk1: u32,
2184 pub bone_index: u16,
2186 pub parent_index: u16,
2188 pub unks: [u32; 7],
2190}
2191
2192#[binread]
2193#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2194#[derive(Debug, Xc3Write, PartialEq, Clone)]
2195#[br(stream = r)]
2196#[xc3(base_offset)]
2197pub struct SkeletonUnk5 {
2198 #[br(temp, try_calc = r.stream_position())]
2199 base_offset: u64,
2200
2201 #[br(parse_with = parse_count32_offset32)]
2202 #[br(args { offset: base_offset, inner: base_offset })]
2203 #[xc3(count_offset(u32, u32))]
2204 pub unk1: Vec<SkeletonUnk5Unk1>,
2205
2206 #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
2208 #[xc3(offset(u32))]
2209 pub unk_offset: Option<[f32; 12]>,
2210
2211 pub unk: [u32; 5],
2213}
2214
2215#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2216#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2217#[br(import_raw(base_offset: u64))]
2218pub struct SkeletonUnk5Unk1 {
2219 pub unk1: [[f32; 4]; 4],
2220 pub unk2: u32,
2221
2222 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2224 #[xc3(count_offset(u32, u32))]
2225 pub unk3: Vec<SkeletonUnk5Unk1Unk3>,
2226
2227 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2228 #[xc3(count_offset(u32, u32))]
2229 pub unk4: Vec<u32>,
2230
2231 pub unk7: [f32; 15],
2232}
2233
2234#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2235#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2236pub struct SkeletonUnk5Unk1Unk3 {
2237 pub unk1: f32,
2238 pub unk2: u16, pub unk3: u16, }
2241
2242#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2244#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2245#[br(import_raw(base_offset: u64))]
2246pub struct AsBoneData {
2247 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
2248 #[xc3(offset_count(u32, u32))]
2249 pub bones: Vec<AsBone>,
2250
2251 #[br(parse_with = parse_offset32_count32, offset = base_offset)]
2252 #[xc3(offset_count(u32, u32))]
2253 pub values: Vec<AsBoneValue>,
2254
2255 #[br(parse_with = parse_ptr32)]
2257 #[br(args { offset: base_offset, inner: args! { count: bones.len() }})]
2258 #[xc3(offset(u32), align(16))]
2259 pub transforms: Vec<AsBoneTransform>,
2260
2261 pub unk3: u32,
2262
2263 pub unk: [u32; 2],
2266}
2267
2268#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2269#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2270pub struct AsBone {
2271 pub bone_index: u16,
2273 pub parent_index: u16,
2275 pub unk_end_index: u16, pub unk_start_index: u16, pub unk1: u16,
2278 pub unk2: u16,
2279 pub value_count: u16,
2280 pub value_start_index: u16,
2282 pub translation: [f32; 3],
2284 pub unk5: [f32; 6], pub rotation_quaternion: [f32; 4],
2287 pub unk6: [f32; 3],
2288}
2289
2290#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2292#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2293pub struct AsBoneValue {
2294 unk1: [f32; 4],
2295 unk2: [f32; 4],
2296 unk3: [f32; 4],
2297 unk4: [f32; 2],
2298}
2299
2300#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2301#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2302pub struct AsBoneTransform {
2303 pub unk1: [[f32; 4]; 4],
2304 pub unk2: [[f32; 4]; 4],
2305 pub unk3: [[f32; 4]; 4],
2306}
2307
2308#[binread]
2310#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2311#[derive(Debug, Xc3Write, PartialEq, Clone)]
2312#[br(stream = r)]
2313#[xc3(base_offset)]
2314pub struct Unk1 {
2315 #[br(temp, try_calc = r.stream_position())]
2316 base_offset: u64,
2317
2318 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2319 #[xc3(count_offset(u32, u32))]
2320 pub unk1: Vec<Unk1Unk1>,
2321
2322 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2323 #[xc3(count_offset(u32, u32))]
2324 pub unk2: Vec<Unk1Unk2>,
2325
2326 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2327 #[xc3(count_offset(u32, u32))]
2328 pub unk3: Vec<Unk1Unk3>,
2329
2330 #[br(parse_with = parse_count32_offset32, offset = base_offset)]
2332 #[xc3(count_offset(u32, u32))]
2333 pub unk4: Vec<Unk1Unk4>,
2334
2335 pub unk: [u32; 4],
2337}
2338
2339#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2340#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2341pub struct Unk1Unk1 {
2342 pub index: u16,
2343 pub unk2: u16, }
2345
2346#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2347#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2348pub struct Unk1Unk2 {
2349 pub unk1: u16, pub index: u16,
2351 pub unk3: u16,
2352 pub unk4: u16,
2353 pub unk5: u32, }
2355
2356#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2357#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2358pub struct Unk1Unk3 {
2359 pub unk1: u16,
2360 pub unk2: u16,
2361 pub unk3: u32,
2362 pub unk4: u16,
2363 pub unk5: u16,
2364 pub unk6: u16,
2365 pub unk7: u16,
2366}
2367
2368#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
2369#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
2370pub struct Unk1Unk4 {
2371 pub unk1: f32,
2372 pub unk2: f32,
2373 pub unk3: f32,
2374 pub unk4: u32,
2375}
2376
2377xc3_write_binwrite_impl!(
2378 ParamType,
2379 RenderPassType,
2380 StateFlags,
2381 ModelsFlags,
2382 SamplerFlags,
2383 TextureUsage,
2384 ExtMeshFlags,
2385 MeshRenderFlags2,
2386 MaterialFlags,
2387 MaterialRenderFlags,
2388 BoneFlags
2389);
2390
2391impl Xc3WriteOffsets for SkinningOffsets<'_> {
2392 type Args = ();
2393
2394 fn write_offsets<W: std::io::Write + std::io::Seek>(
2395 &self,
2396 writer: &mut W,
2397 _base_offset: u64,
2398 data_ptr: &mut u64,
2399 endian: xc3_write::Endian,
2400 _args: Self::Args,
2401 ) -> xc3_write::Xc3Result<()> {
2402 let base_offset = self.base_offset;
2403
2404 let bones = self.bones.write(writer, base_offset, data_ptr, endian)?;
2405
2406 if !self.bone_indices.data.is_empty() {
2407 self.bone_indices
2408 .write_full(writer, base_offset, data_ptr, endian, ())?;
2409 }
2410
2411 self.inverse_bind_transforms
2412 .write_full(writer, base_offset, data_ptr, endian, ())?;
2413
2414 self.constraints
2415 .write_full(writer, base_offset, data_ptr, endian, ())?;
2416 self.bounds
2417 .write_full(writer, base_offset, data_ptr, endian, ())?;
2418
2419 self.unk_offset4
2420 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2421 self.as_bone_data
2422 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2423 self.unk_offset5
2424 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2425
2426 for bone in bones.0 {
2427 bone.name
2428 .write_full(writer, base_offset, data_ptr, endian, ())?;
2429 }
2430 Ok(())
2431 }
2432}
2433
2434impl Xc3WriteOffsets for ModelUnk1Offsets<'_> {
2435 type Args = ();
2436
2437 fn write_offsets<W: std::io::Write + std::io::Seek>(
2438 &self,
2439 writer: &mut W,
2440 _base_offset: u64,
2441 data_ptr: &mut u64,
2442 endian: xc3_write::Endian,
2443 _args: Self::Args,
2444 ) -> xc3_write::Xc3Result<()> {
2445 let base_offset = self.base_offset;
2446
2447 let items1 = self.items1.write(writer, base_offset, data_ptr, endian)?;
2448
2449 self.items3
2450 .write_full(writer, base_offset, data_ptr, endian, ())?;
2451
2452 if !self.items2.data.is_empty() {
2453 self.items2
2454 .write_full(writer, base_offset, data_ptr, endian, ())?;
2455 }
2456
2457 if !self.items4.data.is_empty() {
2459 self.items4
2460 .write_full(writer, base_offset, data_ptr, endian, ())?;
2461 }
2462
2463 for item in items1.0 {
2464 item.name
2465 .write_full(writer, base_offset, data_ptr, endian, ())?;
2466 }
2467
2468 self.extra
2469 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2470
2471 Ok(())
2472 }
2473}
2474
2475impl Xc3WriteOffsets for LodDataOffsets<'_> {
2476 type Args = ();
2477
2478 fn write_offsets<W: std::io::Write + std::io::Seek>(
2479 &self,
2480 writer: &mut W,
2481 _base_offset: u64,
2482 data_ptr: &mut u64,
2483 endian: xc3_write::Endian,
2484 _args: Self::Args,
2485 ) -> xc3_write::Xc3Result<()> {
2486 let base_offset = self.base_offset;
2487 self.groups
2489 .write_full(writer, base_offset, data_ptr, endian, ())?;
2490 self.items
2491 .write_full(writer, base_offset, data_ptr, endian, ())?;
2492 Ok(())
2493 }
2494}
2495
2496impl Xc3WriteOffsets for ModelsV112Offsets<'_> {
2498 type Args = ();
2499
2500 fn write_offsets<W: std::io::Write + std::io::Seek>(
2501 &self,
2502 writer: &mut W,
2503 _base_offset: u64,
2504 data_ptr: &mut u64,
2505 endian: xc3_write::Endian,
2506 _args: Self::Args,
2507 ) -> xc3_write::Xc3Result<()> {
2508 let base_offset = self.base_offset;
2509
2510 self.models
2511 .write_full(writer, base_offset, data_ptr, endian, ())?;
2512 self.skinning
2513 .write_full(writer, base_offset, data_ptr, endian, ())?;
2514 if !self.ext_meshes.data.is_empty() {
2515 self.ext_meshes
2516 .write_full(writer, base_offset, data_ptr, endian, ())?;
2517 }
2518
2519 self.model_unk8
2520 .write_full(writer, base_offset, data_ptr, endian, ())?;
2521
2522 self.morph_controllers
2524 .write_full(writer, base_offset, data_ptr, endian, ())?;
2525
2526 self.lod_data
2528 .write_full(writer, base_offset, data_ptr, endian, ())?;
2529 self.model_unk7
2530 .write_full(writer, base_offset, data_ptr, endian, ())?;
2531 self.model_unk11
2532 .write_full(writer, base_offset, data_ptr, endian, ())?;
2533 self.model_unk1
2534 .write_full(writer, base_offset, data_ptr, endian, ())?;
2535 self.model_unk12
2536 .write_full(writer, base_offset, data_ptr, endian, ())?;
2537 self.alpha_table
2538 .write_full(writer, base_offset, data_ptr, endian, ())?;
2539 self.model_unk3
2540 .write_full(writer, base_offset, data_ptr, endian, ())?;
2541 self.model_unk9
2542 .write_full(writer, base_offset, data_ptr, endian, ())?;
2543 self.extra
2544 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2545
2546 Ok(())
2547 }
2548}
2549
2550impl Xc3WriteOffsets for TechniqueOffsets<'_> {
2551 type Args = ();
2552
2553 fn write_offsets<W: std::io::Write + std::io::Seek>(
2554 &self,
2555 writer: &mut W,
2556 base_offset: u64,
2557 data_ptr: &mut u64,
2558 endian: xc3_write::Endian,
2559 _args: Self::Args,
2560 ) -> xc3_write::Xc3Result<()> {
2561 self.attributes
2563 .write_full(writer, base_offset, data_ptr, endian, ())?;
2564 if !self.textures.data.is_empty() {
2565 self.textures
2567 .write_full(writer, base_offset, data_ptr, endian, ())?;
2568 }
2569 self.uniform_blocks
2570 .write_full(writer, base_offset, data_ptr, endian, ())?;
2571
2572 self.parameters
2573 .write_full(writer, base_offset, data_ptr, endian, ())?;
2574
2575 self.unk15
2576 .write_full(writer, base_offset, data_ptr, endian, ())?;
2577
2578 *data_ptr += self.parameters.data.len() as u64 * 16;
2581
2582 Ok(())
2583 }
2584}
2585
2586impl Xc3WriteOffsets for MaterialsOffsets<'_> {
2588 type Args = ();
2589
2590 fn write_offsets<W: std::io::Write + std::io::Seek>(
2591 &self,
2592 writer: &mut W,
2593 _base_offset: u64,
2594 data_ptr: &mut u64,
2595 endian: xc3_write::Endian,
2596 _args: Self::Args,
2597 ) -> xc3_write::Xc3Result<()> {
2598 let base_offset = self.base_offset;
2599
2600 let materials = self
2602 .materials
2603 .write(writer, base_offset, data_ptr, endian)?;
2604
2605 self.work_values
2606 .write_full(writer, base_offset, data_ptr, endian, ())?;
2607 self.shader_vars
2608 .write_full(writer, base_offset, data_ptr, endian, ())?;
2609
2610 for material in &materials.0 {
2611 material
2612 .techniques
2613 .write_full(writer, base_offset, data_ptr, endian, ())?;
2614 }
2615
2616 for material in &materials.0 {
2617 material
2618 .textures
2619 .write_full(writer, base_offset, data_ptr, endian, ())?;
2620 }
2621
2622 if !self.alpha_test_textures.data.is_empty() {
2624 self.alpha_test_textures
2625 .write_full(writer, base_offset, data_ptr, endian, ())?;
2626 }
2627 self.callbacks
2628 .write_full(writer, base_offset, data_ptr, endian, ())?;
2629 self.material_unk2
2630 .write_full(writer, base_offset, data_ptr, endian, ())?;
2631 self.fur_shells
2632 .write_full(writer, base_offset, data_ptr, endian, ())?;
2633 self.samplers
2634 .write_full(writer, base_offset, data_ptr, endian, ())?;
2635 self.unk6
2636 .write_full(writer, base_offset, data_ptr, endian, ())?;
2637 self.unk5
2638 .write_offsets(writer, base_offset, data_ptr, endian, ())?;
2639
2640 self.techniques
2641 .write_full(writer, base_offset, data_ptr, endian, ())?;
2642
2643 for material in &materials.0 {
2645 material
2646 .name
2647 .write_full(writer, base_offset, data_ptr, endian, ())?;
2648 }
2649
2650 Ok(())
2651 }
2652}
2653
2654impl Xc3WriteOffsets for MxmdV112Offsets<'_> {
2655 type Args = ();
2656
2657 fn write_offsets<W: std::io::Write + std::io::Seek>(
2658 &self,
2659 writer: &mut W,
2660 base_offset: u64,
2661 data_ptr: &mut u64,
2662 endian: xc3_write::Endian,
2663 _args: Self::Args,
2664 ) -> xc3_write::Xc3Result<()> {
2665 self.models
2666 .write_full(writer, base_offset, data_ptr, endian, ())?;
2667 self.unk8
2668 .write_full(writer, base_offset, data_ptr, endian, ())?;
2669 self.materials
2670 .write_full(writer, base_offset, data_ptr, endian, ())?;
2671
2672 self.streaming
2674 .write_full(writer, base_offset, data_ptr, endian, ())?;
2675
2676 vec![0u8; (data_ptr.next_multiple_of(16) - *data_ptr) as usize]
2678 .xc3_write(writer, endian)?;
2679 *data_ptr = (*data_ptr).max(writer.stream_position()?);
2680
2681 self.unk1
2683 .write_full(writer, base_offset, data_ptr, endian, ())?;
2684
2685 self.vertex_data
2686 .write_full(writer, base_offset, data_ptr, endian, ())?;
2687 self.spch
2688 .write_full(writer, base_offset, data_ptr, endian, ())?;
2689 self.packed_textures
2690 .write_full(writer, base_offset, data_ptr, endian, ())?;
2691
2692 Ok(())
2695 }
2696}
2697
2698impl Xc3WriteOffsets for Unk1Offsets<'_> {
2700 type Args = ();
2701
2702 fn write_offsets<W: std::io::Write + std::io::Seek>(
2703 &self,
2704 writer: &mut W,
2705 _base_offset: u64,
2706 data_ptr: &mut u64,
2707 endian: xc3_write::Endian,
2708 _args: Self::Args,
2709 ) -> xc3_write::Xc3Result<()> {
2710 let base_offset = self.base_offset;
2711 self.unk1
2712 .write_full(writer, base_offset, data_ptr, endian, ())?;
2713 self.unk2
2714 .write_full(writer, base_offset, data_ptr, endian, ())?;
2715 self.unk3
2716 .write_full(writer, base_offset, data_ptr, endian, ())?;
2717 if !self.unk4.data.is_empty() {
2718 self.unk4
2719 .write_full(writer, base_offset, data_ptr, endian, ())?;
2720 }
2721 Ok(())
2722 }
2723}
2724
2725impl Xc3WriteOffsets for ModelUnk3ItemOffsets<'_> {
2726 type Args = ();
2727
2728 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2729 &self,
2730 writer: &mut W,
2731 base_offset: u64,
2732 data_ptr: &mut u64,
2733 endian: xc3_write::Endian,
2734 _args: Self::Args,
2735 ) -> xc3_write::Xc3Result<()> {
2736 self.unk3
2738 .write_full(writer, base_offset, data_ptr, endian, ())?;
2739 self.name
2740 .write_full(writer, base_offset, data_ptr, endian, ())?;
2741 Ok(())
2742 }
2743}
2744
2745impl Xc3WriteOffsets for FurShellsOffsets<'_> {
2746 type Args = ();
2747
2748 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2749 &self,
2750 writer: &mut W,
2751 base_offset: u64,
2752 data_ptr: &mut u64,
2753 endian: xc3_write::Endian,
2754 _args: Self::Args,
2755 ) -> xc3_write::Xc3Result<()> {
2756 self.params
2758 .write_full(writer, base_offset, data_ptr, endian, ())?;
2759 self.material_param_indices
2760 .write_full(writer, base_offset, data_ptr, endian, ())?;
2761 Ok(())
2762 }
2763}
2764
2765impl Xc3WriteOffsets for PackedTexturesOffsets<'_> {
2766 type Args = ();
2767
2768 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2769 &self,
2770 writer: &mut W,
2771 _base_offset: u64,
2772 data_ptr: &mut u64,
2773 endian: xc3_write::Endian,
2774 _args: Self::Args,
2775 ) -> xc3_write::Xc3Result<()> {
2776 let base_offset = self.base_offset;
2777
2778 let textures = self.textures.write(writer, base_offset, data_ptr, endian)?;
2780
2781 self.strings_offset
2782 .write_full(writer, base_offset, data_ptr, endian, ())?;
2783 for texture in &textures.0 {
2784 texture
2785 .name
2786 .write_full(writer, base_offset, data_ptr, endian, ())?;
2787 }
2788 for texture in &textures.0 {
2789 texture
2790 .mibl_data
2791 .write_full(writer, base_offset, data_ptr, endian, ())?;
2792 }
2793 Ok(())
2794 }
2795}
2796
2797impl<U> Xc3WriteOffsets for PackedExternalTexturesOffsets<'_, U>
2798where
2799 U: Xc3Write + 'static,
2800 for<'b> U: BinRead<Args<'b> = ()>,
2801 for<'b> U::Offsets<'b>: Xc3WriteOffsets<Args = ()>,
2802{
2803 type Args = ();
2804
2805 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2806 &self,
2807 writer: &mut W,
2808 _base_offset: u64,
2809 data_ptr: &mut u64,
2810 endian: xc3_write::Endian,
2811 _args: Self::Args,
2812 ) -> xc3_write::Xc3Result<()> {
2813 let base_offset = self.base_offset;
2814
2815 let textures = self.textures.write(writer, base_offset, data_ptr, endian)?;
2817
2818 self.strings_offset
2819 .write_full(writer, base_offset, data_ptr, endian, ())?;
2820 for texture in &textures.0 {
2821 texture
2822 .name
2823 .write_full(writer, base_offset, data_ptr, endian, ())?;
2824 }
2825 Ok(())
2826 }
2827}
2828
2829impl Xc3WriteOffsets for SkeletonUnk5Offsets<'_> {
2830 type Args = ();
2831
2832 fn write_offsets<W: std::io::Write + std::io::Seek>(
2833 &self,
2834 writer: &mut W,
2835 _base_offset: u64,
2836 data_ptr: &mut u64,
2837 endian: xc3_write::Endian,
2838 _args: Self::Args,
2839 ) -> xc3_write::Xc3Result<()> {
2840 let base_offset = self.base_offset;
2841
2842 let unk1 = self.unk1.write(writer, base_offset, data_ptr, endian)?;
2843 for u in &unk1.0 {
2844 u.unk3
2845 .write_full(writer, base_offset, data_ptr, endian, ())?;
2846 }
2847 for u in &unk1.0 {
2848 u.unk4
2849 .write_full(writer, base_offset, data_ptr, endian, ())?;
2850 }
2851 self.unk_offset
2852 .write_full(writer, base_offset, data_ptr, endian, ())?;
2853
2854 Ok(())
2855 }
2856}
2857
2858impl Xc3WriteOffsets for Unk8Offsets<'_> {
2859 type Args = ();
2860 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2861 &self,
2862 writer: &mut W,
2863 _base_offset: u64,
2864 data_ptr: &mut u64,
2865 endian: xc3_write::Endian,
2866 _args: Self::Args,
2867 ) -> xc3_write::Xc3Result<()> {
2868 let base_offset = self.base_offset;
2869 let unk2 = self.unk2.write(writer, base_offset, data_ptr, endian)?;
2870 self.unk3
2871 .write_full(writer, base_offset, data_ptr, endian, ())?;
2872 for u in unk2.0 {
2874 u.name
2875 .write_full(writer, base_offset, data_ptr, endian, ())?;
2876 }
2877 Ok(())
2878 }
2879}
2880
2881impl Xc3WriteOffsets for ModelUnk9InnerUnk0Offsets<'_> {
2882 type Args = ();
2883
2884 fn write_offsets<W: std::io::Write + std::io::Seek>(
2885 &self,
2886 writer: &mut W,
2887 _base_offset: u64,
2888 data_ptr: &mut u64,
2889 endian: xc3_write::Endian,
2890 args: Self::Args,
2891 ) -> xc3_write::Xc3Result<()> {
2892 let base_offset = self.base_offset.saturating_sub(4);
2894 if !self.items1.data.is_empty() {
2895 self.items1
2896 .write_full(writer, base_offset, data_ptr, endian, args)?;
2897 }
2898 if !self.items2.data.is_empty() {
2899 self.items2
2900 .write_full(writer, base_offset, data_ptr, endian, args)?;
2901 }
2902 Ok(())
2903 }
2904}
2905
2906impl Xc3WriteOffsets for MaterialCallbacksOffsets<'_> {
2907 type Args = ();
2908 fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
2909 &self,
2910 writer: &mut W,
2911 base_offset: u64,
2912 data_ptr: &mut u64,
2913 endian: xc3_write::Endian,
2914 _args: Self::Args,
2915 ) -> xc3_write::Xc3Result<()> {
2916 self.work_callbacks
2918 .write_full(writer, base_offset, data_ptr, endian, ())?;
2919 self.unk1
2920 .write_full(writer, base_offset, data_ptr, endian, ())?;
2921 self.material_indices
2922 .write_full(writer, base_offset, data_ptr, endian, ())?;
2923 Ok(())
2924 }
2925}
2926
2927fn count_constraints(bones: &[Bone]) -> usize {
2928 bones
2930 .iter()
2931 .map(|b| {
2932 if b.flags.distance_constraint() || b.flags.fixed_offset_constraint() {
2933 b.constraint_index as usize + 1
2934 } else {
2935 0
2936 }
2937 })
2938 .max()
2939 .unwrap_or_default()
2940}
2941
2942fn count_bounds(bones: &[Bone]) -> usize {
2943 bones
2945 .iter()
2946 .map(|b| {
2947 if b.flags.bounds_offset() {
2948 b.bounds_index as usize + 1
2949 } else {
2950 0
2951 }
2952 })
2953 .max()
2954 .unwrap_or_default()
2955}
2956
2957fn model_unk9_buffer_length(buffers: &[ModelUnk9Buffer]) -> usize {
2958 buffers
2960 .iter()
2961 .max_by_key(|b| b.offset)
2962 .map(|b| b.offset as usize + b.count as usize * 48)
2963 .unwrap_or_default()
2964}