1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
//! Vertex and geometry data for models and map models.
//!
//! # Overview
//! A [VertexData] file stores model geometry in a combined [buffer](struct.VertexData.html#structfield.buffer).
//! The remaining fields describe the data stored in the buffer like vertices or morph targets.
//!
//! Each [Mesh](crate::mxmd::Mesh) draw call references a [VertexBufferDescriptor] and [IndexBufferDescriptor].
//! Vertex buffers except the weights buffer have an associated [VertexBufferExtInfo]
//! for assigning additional data like outline buffers or morph targets.
//!
//! The weights buffer just contains [DataType::SkinWeights] and [DataType::BoneIndices].
//! This buffer is shared between all vertex buffers with
//! each buffer selecting weight buffer "vertices" using [DataType::WeightIndex]
//! and additional indexing information defined in [Weights].
//! See [xc3_model](https://docs.rs/xc3_model) for the complete indexing implementation.
//!
//! Some vertex buffers have optional morph targets assigned in [VertexMorphs].
//! Morph targets define a default target for the neutral pose as well as additional
//! targets applied on top of the default target.
//! Morph targets define attributes not present in the vertex buffer and have a
//! final attribute value defined as `default + target_delta * weight`
//! where `target_delta` is defined sparsely using a list of deltas and vertex indices.
//!
//! # Attribute Layout
//! The sections of the byte buffer for each descriptor contain each attribute for each vertex in order.
//! This interleaved or "array of structs" layout is cache friendly when accessing each attribute for each vertex
//! like in the vertex shaders in game.
//! ```text
//! position 0
//! normal 0
//! position 1
//! normal 1
//! ...
//! ```
//! Applications tend to work better with a "struct of arrays" approach where
//! dedicated arrays store the values for a single attribute for all items.
//! This approach is cache friendly when accessing the same attribute for all vertices
//! and allows for easily adding and removing attributes.
//! This is the approach used by [xc3_model](https://docs.rs/xc3_model).
//! ```text
//! position 0
//! position 1
//! ...
//! ```
//! ```text
//! normal 0
//! normal 1
//! ...
//! ```
use crate::{
    parse_count16_offset32, parse_count32_offset32, parse_offset32_count32, parse_opt_ptr32,
    parse_ptr32, xc3_write_binwrite_impl,
};
use bilge::prelude::*;
use binrw::{args, binread, BinRead, BinWrite};
use xc3_write::{Xc3Write, Xc3WriteOffsets};

/// Vertex and vertex index buffer data used by a [Model](crate::mxmd::Model).
#[binread]
#[derive(Debug, Xc3Write, PartialEq, Clone)]
#[br(stream = r)]
#[xc3(base_offset)]
pub struct VertexData {
    #[br(temp, try_calc = r.stream_position())]
    base_offset: u64,

    // TODO: Sometimes 80 and sometimes 84?
    #[br(parse_with = parse_offset32_count32, args { offset: base_offset, inner: base_offset })]
    #[xc3(offset_count(u32, u32))]
    pub vertex_buffers: Vec<VertexBufferDescriptor>,

    #[br(parse_with = parse_offset32_count32, offset = base_offset)]
    #[xc3(offset_count(u32, u32))]
    pub index_buffers: Vec<IndexBufferDescriptor>,

    // padding?
    pub unk0: u32,
    pub unk1: u32,
    pub unk2: u32,

    #[br(parse_with = parse_ptr32)]
    #[br(args { offset: base_offset, inner: args! { count: buffer_info_count(&vertex_buffers) }})]
    #[xc3(offset(u32))]
    pub vertex_buffer_info: Vec<VertexBufferExtInfo>,

    // 332 bytes of data?
    #[br(parse_with = parse_offset32_count32, offset = base_offset)]
    #[xc3(offset_count(u32, u32))]
    pub outline_buffers: Vec<OutlineBuffer>,

    #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
    #[xc3(offset(u32))]
    pub vertex_morphs: Option<VertexMorphs>,

    /// The data buffer containing all the geometry data.
    #[br(parse_with = parse_count32_offset32, offset = base_offset)]
    #[xc3(count_offset(u32, u32), align(4096))]
    pub buffer: Vec<u8>,

    // TODO: particles?
    #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
    #[xc3(offset(u32))]
    pub unk_data: Option<UnkData>,

    #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
    #[xc3(offset(u32))]
    pub weights: Option<Weights>,

    #[br(parse_with = parse_opt_ptr32, offset = base_offset)]
    #[xc3(offset(u32))]
    pub unk7: Option<Unk>,

    // TODO: padding?
    pub unks: [u32; 5],
}

#[derive(Debug, BinRead, Xc3Write, PartialEq, Eq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct VertexBufferDescriptor {
    /// The offset into [buffer](struct.VertexData.html#structfield.buffer).
    pub data_offset: u32,
    pub vertex_count: u32,
    /// The size or stride of the vertex in bytes.
    pub vertex_size: u32,

    /// A tightly packed list of attributes for the data for this buffer.
    #[br(parse_with = parse_offset32_count32, offset = base_offset)]
    #[xc3(offset_count(u32, u32))]
    pub attributes: Vec<VertexAttribute>,

    pub unk1: u32,
    pub unk2: u32,
    pub unk3: u32,
}

/// A single attribute in a [VertexBufferDescriptor] like positions or normals.
///
/// Attributes are tightly packed, so the relative offset is
/// the sum of previous attribute sizes.
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Eq, Clone, Copy)]
pub struct VertexAttribute {
    pub data_type: DataType,
    /// The size in bytes of [data_type](#structfield.data_type).
    pub data_size: u16,
}

// Format is taken from RenderDoc debugging.
// Names are taken from shader attribute metadata.
/// The data type, usage, and component count for a [VertexAttribute].
#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum DataType {
    /// Float32x3 "vPos" in shaders.
    Position = 0,
    /// ??? "fWeight" in shaders.
    Unk1 = 1,
    Unk2 = 2,
    /// Uint16x2 "nWgtIdx" in shaders.
    ///
    /// The index in the first component selects elements in the precomputed skinning matrices in the vertex shader.
    /// See [Weights] for details.
    WeightIndex = 3,
    /// Uint16x2 "nWgtIdx" in shaders.
    ///
    /// Used for some stage models.
    WeightIndex2 = 4,
    /// Float32x2 "vTex0" in shaders.
    TexCoord0 = 5,
    /// Float32x2 "vTex1" in shaders.
    TexCoord1 = 6,
    /// Float32x2 "vTex2" in shaders.
    TexCoord2 = 7,
    /// Float32x2 "vTex3" in shaders.
    TexCoord3 = 8,
    /// Float32x2 "vTex4" in shaders.
    TexCoord4 = 9,
    /// Float32x2 "vTex5" in shaders.
    TexCoord5 = 10,
    /// Float32x2 "vTex6" in shaders.
    TexCoord6 = 11,
    /// Float32x2 "vTex7" in shaders.
    TexCoord7 = 12,
    /// Float32x2 "vTex8" in shaders.
    TexCoord9 = 13,
    /// Unorm8x4 "vBlend" in shaders.
    Blend = 14,
    Unk15 = 15,
    Unk16 = 16,
    /// Unorm8x4 "vColor" in shaders.
    VertexColor = 17,
    Unk18 = 18,
    /// ??? "vGmCal1" in shaders.
    Unk24 = 24,
    /// ??? "vGmCal2" in shaders.
    Unk25 = 25,
    /// ??? "vGmCal3" in shaders.
    Unk26 = 26,
    /// Snorm8x4 "vNormal" in shaders.
    Normal = 28,
    /// Snorm8x4 "vTan" in shaders with bitangent sign in the fourth component.
    Tangent = 29,
    /// ??? "fGmAl" in shaders.
    Unk30 = 30,
    /// Snorm8x4 "vNormal" in shaders.
    Normal2 = 32,
    Unk33 = 33,
    /// Snorm8x4 "vNormal" in shaders.
    Normal3 = 34,
    /// Unorm8x4 "vColor" in shaders.
    VertexColor3 = 35,
    /// Float32x3 "vPos" in shaders.
    Position2 = 36,
    /// Unorm8x4 "vNormal" in shaders.
    Normal4 = 37,
    /// Float32x3 "vOldPos" in shaders.
    OldPosition = 39,
    /// Unorm8x4 "vTan" in shaders.
    Tangent2 = 40,
    /// Unorm16x4 skin weights for up to 4 bone influences.
    SkinWeights = 41,
    /// Uint8x4 bone indices for up to 4 bone infuences in the [Skinning](crate::mxmd::Skinning) in the [Mxmd](crate::mxmd::Mxmd).
    BoneIndices = 42,
    /// ??? "vFlow" in shaders.
    Flow = 52,
}

// TODO: Is this data always u16?
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Eq, Clone)]
pub struct IndexBufferDescriptor {
    /// The offset into [buffer](struct.VertexData.html#structfield.buffer).
    pub data_offset: u32,
    pub index_count: u32,
    pub unk1: Unk1, // TODO: primitive type?
    pub unk2: Unk2, // TODO: index format?
    // TODO: padding?
    pub unk3: u32,
    pub unk4: u32,
}

#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum Unk1 {
    Unk0 = 0,
    Unk3 = 3,
}

#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum Unk2 {
    Unk0 = 0,
}

/// Vertex animation data often called "vertex morphs", "shape keys", or "blend shapes".
#[derive(Debug, BinRead, Xc3Write, Clone, PartialEq)]
pub struct VertexMorphs {
    #[br(parse_with = parse_count32_offset32)]
    #[xc3(count_offset(u32, u32))]
    pub descriptors: Vec<MorphDescriptor>,

    #[br(parse_with = parse_count32_offset32)]
    #[xc3(count_offset(u32, u32))]
    pub targets: Vec<MorphTarget>,

    // TODO: padding?
    pub unks: [u32; 4],
}

#[derive(Debug, BinRead, Xc3Write, Clone, PartialEq)]
pub struct MorphDescriptor {
    pub vertex_buffer_index: u32,
    pub target_start_index: u32,
    pub target_count: u32,

    // TODO: count_offset?
    // pointer to u16 indices 0,1,2,...?
    // start and ending frame for each target?
    #[br(parse_with = parse_ptr32)]
    #[br(args { inner: args! { count: target_count as usize }})]
    #[xc3(offset(u32))]
    pub unk1: Vec<u16>,

    // flags?
    pub unk2: u32,
}

// TODO: vertex attributes for vertex animation data?
/// A set of target vertex values similar to a keyframe in traditional animations.
#[derive(Debug, BinRead, BinWrite, Clone, PartialEq)]
pub struct MorphTarget {
    /// Relative to [data_base_offset](struct.ModelData.html#structfield.data_base_offset)
    pub data_offset: u32,
    pub vertex_count: u32,
    pub vertex_size: u32,

    pub flags: MorphTargetFlags,
}

#[bitsize(32)]
#[derive(DebugBits, FromBits, BinRead, BinWrite, Clone, Copy, PartialEq)]
#[br(map = u32::into)]
#[bw(map = |&x| u32::from(x))]
pub struct MorphTargetFlags {
    pub unk1: u16,                 // always 0?
    pub blend_target_buffer: bool, // once per descriptor?
    pub default_buffer: bool,      // once per descriptor?
    pub param_buffer: bool,
    pub unk5: u13, // always 0?
}

/// Information used for precomputing skinning matrices
/// based on a mesh's level of detail (LOD) and [RenderPassType](crate::mxmd::RenderPassType).
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, Clone, PartialEq)]
pub struct Weights {
    /// Selected based on the associated [WeightLod] for a [Mesh](crate::mxmd::Mesh).
    #[br(parse_with = parse_count32_offset32)]
    #[xc3(count_offset(u32, u32))]
    pub groups: Vec<WeightGroup>,

    /// The descriptor in [vertex_buffers](struct.VertexData.html#structfield.vertex_buffer) containing the weight data.
    /// This is typically the last element.
    pub vertex_buffer_index: u16,

    /// Selected based on the LOD of the [Mesh](crate::mxmd::Mesh).
    #[br(parse_with = parse_count16_offset32)]
    #[xc3(count_offset(u16, u32))]
    pub weight_lods: Vec<WeightLod>,

    pub unk4: u32,
    pub unks5: [u32; 4], // padding?
}

/// A range of elements in the weights buffer.
/// Each element in the weights buffer is part of at least one [WeightGroup].
///
/// The [input_start_index](#structfield.input_start_index) and [count](#structfield.count)
/// select a range of [DataType::BoneIndices] and [DataType::SkinWeights] from the weights buffer.
/// The bone matrices for each bone index multiplied by the weights are written to the output buffer starting at [output_start_index](#structfield.output_start_index).
/// This precomputed skinning buffer is used to select transforms in the vertex shader using [DataType::WeightIndex].
#[derive(Debug, Clone, PartialEq, BinRead, Xc3Write, Xc3WriteOffsets)]
pub struct WeightGroup {
    /// Index into the skinning buffer used in the vertex shader with bone transforms multiplied by skin weights.
    /// These weighted bone matrices are selected using [DataType::WeightIndex].
    pub output_start_index: u32,
    /// Start of the elements in the weights buffer at [vertex_buffer_index](struct.Weights.html#structfield.vertex_buffer_index).
    pub input_start_index: u32,
    /// Number of elements in the weights buffer.
    pub count: u32,
    pub unks: [u32; 4], // TODO: always 0?
    /// Index into [group_indices_plus_one](struct.WeightLod.html#structfield.group_indices_plus_one)
    /// pointing back to this group.
    pub lod_group_index: u8,
    /// Index into [weight_lods](struct.Weights.html#structfield.weight_lods)
    /// for the [WeightLod] that references this [WeightGroup].
    pub lod_index: u8,
    /// The max number of non-zero bone influences per vertex
    /// for the range of elements in the weights buffer.
    pub max_influences: u8,
    pub unk4: u8,
    pub unks2: [u32; 2],
}

// TODO: The material's pass index indexes into this?
// TODO: Figure out by finding files with no more groups than pass ids?
/// References to [WeightGroup] for each of the [RenderPassType](crate::mxmd::RenderPassType).
#[derive(Debug, Clone, PartialEq, BinRead, Xc3Write, Xc3WriteOffsets)]
pub struct WeightLod {
    /// One plus the indices pointing back to [groups](struct.Weights.html#structfield.groups).
    /// Unused entries use the value `0`.
    ///
    /// Each [Mesh](crate::mxmd::Mesh) indexes into this list using a hardcoded remapping
    /// for the [RenderPassType](crate::mxmd::RenderPassType) of the assigned material.
    // TODO: Document each entry.
    pub group_indices_plus_one: [u16; 9],
}

#[binread]
#[derive(Debug, Xc3Write, Xc3WriteOffsets, Clone, PartialEq)]
#[br(stream = r)]
#[xc3(base_offset)]
pub struct Unk {
    #[br(temp, try_calc = r.stream_position())]
    base_offset: u64,

    #[br(parse_with = parse_count32_offset32, offset = base_offset)]
    #[xc3(count_offset(u32, u32))]
    pub unk1: Vec<UnkInner>,

    // The length of the data in bytes.
    pub data_length: u32,

    /// The offset into [buffer](struct.VertexData.html#structfield.buffer).
    pub data_offset: u32,

    // TODO: Padding?
    pub unks: [u32; 8],
}

#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, Clone, PartialEq)]
pub struct UnkInner {
    pub unk1: u16,
    pub unk2: u16,
    pub count: u32,
    pub offset: u32,
    pub unk5: u32,
    // sum of previous counts?
    pub start_index: u32,
}

/// Extra data assigned to a non skin weights buffer.
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, Clone, PartialEq)]
pub struct VertexBufferExtInfo {
    pub flags: VertexBufferExtInfoFlags,
    // TODO: Extra attributes for outline meshes?
    pub outline_buffer_index: u16,
    /// Identical to [target_start_index](struct.MorphDescriptor.html#structfield.target_start_index)
    /// for the corresponding [MorphDescriptor].
    pub morph_target_start_index: u16,
    // TODO: Why is this off by 2?
    /// Identical to [target_count](struct.MorphDescriptor.html#structfield.target_count) + 2
    /// for the corresponding [MorphDescriptor].
    pub morph_target_count: u16,
    // TODO: padding?
    pub unk: u32,
}

#[bitsize(16)]
#[derive(DebugBits, FromBits, BinRead, BinWrite, Clone, Copy, PartialEq)]
#[br(map = u16::into)]
#[bw(map = |&x| u16::from(x))]
pub struct VertexBufferExtInfoFlags {
    pub has_outline_buffer: bool,
    pub unk2: bool,
    pub unk: u14,
}

#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, Clone, PartialEq)]
pub struct OutlineBuffer {
    /// The offset into [buffer](struct.VertexData.html#structfield.buffer).
    pub data_offset: u32,
    pub vertex_count: u32,
    /// The size or stride of the vertex in bytes.
    pub vertex_size: u32,
    // TODO: padding?
    pub unk: u32,
}

#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct UnkData {
    pub unk: [u32; 17],
}

xc3_write_binwrite_impl!(DataType, Unk1, Unk2, MorphTarget, VertexBufferExtInfoFlags);

fn buffer_info_count(vertex_buffers: &[VertexBufferDescriptor]) -> usize {
    // TODO: Extra data for every buffer except the single weights buffer?
    vertex_buffers
        .iter()
        .filter(|b| {
            !b.attributes
                .iter()
                .any(|a| a.data_type == DataType::SkinWeights)
        })
        .count()
}

impl<'a> Xc3WriteOffsets for VertexDataOffsets<'a> {
    fn write_offsets<W: std::io::Write + std::io::Seek>(
        &self,
        writer: &mut W,
        _base_offset: u64,
        data_ptr: &mut u64,
    ) -> xc3_write::Xc3Result<()> {
        let base_offset = self.base_offset;

        let vertex_buffers = self
            .vertex_buffers
            .write_offset(writer, base_offset, data_ptr)?;
        self.index_buffers
            .write_offset(writer, base_offset, data_ptr)?;
        self.vertex_buffer_info
            .write_offset(writer, base_offset, data_ptr)?;

        // TODO: Do all empty lists use offset 0?
        if !self.outline_buffers.data.is_empty() {
            self.outline_buffers
                .write_offset(writer, base_offset, data_ptr)?;
        }

        // The first attribute is aligned to 16.
        // TODO: This doesn't always happen?
        // *data_ptr = data_ptr.next_multiple_of(16);
        for vertex_buffer in vertex_buffers.0 {
            vertex_buffer
                .attributes
                .write_offset(writer, base_offset, data_ptr)?;
        }

        self.weights.write_full(writer, base_offset, data_ptr)?;

        self.unk_data.write_offset(writer, base_offset, data_ptr)?;

        if let Some(vertex_animation) =
            self.vertex_morphs
                .write_offset(writer, base_offset, data_ptr)?
        {
            let descriptors =
                vertex_animation
                    .descriptors
                    .write_offset(writer, base_offset, data_ptr)?;
            vertex_animation
                .targets
                .write_offset(writer, base_offset, data_ptr)?;

            for descriptor in descriptors.0 {
                descriptor
                    .unk1
                    .write_offset(writer, base_offset, data_ptr)?;
            }
        }

        self.unk7.write_full(writer, base_offset, data_ptr)?;

        self.buffer.write_offset(writer, base_offset, data_ptr)?;

        Ok(())
    }
}