physis/
model_vertex_declarations.rs

1// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use crate::model::NUM_VERTICES;
5use binrw::{BinRead, BinResult, BinWrite, binrw};
6use std::io::SeekFrom;
7
8/// Marker for end of stream (0xFF)
9const END_OF_STREAM: u8 = 0xFF;
10
11/// The format of the vertex stream.
12#[binrw]
13#[brw(repr = u8)]
14#[repr(u8)]
15#[derive(Copy, Clone, Debug, PartialEq)]
16pub enum VertexType {
17    /// 1 32-bit float
18    Single1 = 0,
19    /// 2 32-bit floats
20    Single2 = 1,
21    /// 3 32-bit floats
22    Single3 = 2,
23    /// 4 32-bit floats
24    Single4 = 3,
25
26    /// 4 bytes
27    Byte4 = 5,
28
29    /// 2 16-bit signed integers
30    Short2 = 6,
31    /// 4 16-bit signed integers
32    Short4 = 7,
33
34    /// 4 8-bit floats
35    ByteFloat4 = 8,
36
37    /// Duplicate of Short2?
38    Short2n = 9,
39    /// Duplicate of Short4?
40    Short4n = 10,
41
42    /// 2 16-bit floats
43    Half2 = 13,
44    /// 4 16-bit floats
45    Half4 = 14,
46
47    /// 2 16-bit unsigned integers
48    UnsignedShort2 = 16,
49    /// 4 16-bit unsigned integers
50    UnsignedShort4 = 17,
51}
52
53/// In bytes
54pub fn get_vertex_type_size(vertex_type: VertexType) -> usize {
55    // TODO: Most of these are wrong
56    match vertex_type {
57        VertexType::Single1 => 4,
58        VertexType::Single2 => 8,
59        VertexType::Single3 => 12,
60        VertexType::Single4 => 16,
61        VertexType::Byte4 => 4,
62        VertexType::Short2 => 4,
63        VertexType::Short4 => 8,
64        VertexType::ByteFloat4 => 4,
65        VertexType::Short2n => 4,
66        VertexType::Short4n => 4,
67        VertexType::Half2 => 4,
68        VertexType::Half4 => 8,
69        VertexType::UnsignedShort2 => 4,
70        VertexType::UnsignedShort4 => 8,
71    }
72}
73
74/// What the vertex stream is used for.
75#[binrw]
76#[brw(repr = u8)]
77#[repr(u8)]
78#[derive(Copy, Clone, Debug, PartialEq)]
79pub enum VertexUsage {
80    Position = 0,
81    BlendWeights = 1,
82    BlendIndices = 2,
83    Normal = 3,
84    UV = 4,
85    Tangent = 5,
86    BiTangent = 6,
87    Color = 7,
88}
89
90/// Represents an element within a bigger vertex stream.
91#[binrw]
92#[derive(Copy, Clone, Debug, PartialEq)]
93#[allow(dead_code)]
94#[repr(C)]
95#[brw(little)]
96pub struct VertexElement {
97    pub stream: u8,
98    pub offset: u8,
99    pub vertex_type: VertexType,
100    pub vertex_usage: VertexUsage,
101    #[brw(pad_after = 3)]
102    pub usage_index: u8,
103}
104
105/// Represents the true size of VertexElement. Always use this value instead of std::mem::size_of.
106// 3 extra bytes to account for the padding that doesn't appear in the struct itself
107pub const VERTEX_ELEMENT_SIZE: usize = std::mem::size_of::<VertexElement>() + 3;
108
109#[derive(Clone, Debug, PartialEq)]
110pub struct VertexDeclaration {
111    pub elements: Vec<VertexElement>,
112}
113
114#[binrw::parser(reader, endian)]
115pub(crate) fn vertex_element_parser(count: u16) -> BinResult<Vec<VertexDeclaration>> {
116    let mut vertex_declarations: Vec<VertexDeclaration> =
117        vec![VertexDeclaration { elements: vec![] }; count.into()];
118    for declaration in &mut vertex_declarations {
119        let mut element = VertexElement::read_options(reader, endian, ())?;
120
121        loop {
122            declaration.elements.push(element);
123
124            element = VertexElement::read_options(reader, endian, ())?;
125
126            if element.stream == END_OF_STREAM {
127                break;
128            }
129        }
130
131        let to_seek = NUM_VERTICES as usize * 8 - (declaration.elements.len() + 1) * 8;
132        reader.seek(SeekFrom::Current(to_seek as i64))?;
133    }
134
135    Ok(vertex_declarations)
136}
137
138#[binrw::writer(writer, endian)]
139pub(crate) fn vertex_element_writer(declarations: &Vec<VertexDeclaration>) -> BinResult<()> {
140    // write vertex declarations
141    for declaration in declarations {
142        for element in &declaration.elements {
143            element.write_options(writer, endian, ())?;
144        }
145
146        VertexElement {
147            stream: END_OF_STREAM,
148            offset: 0,
149            vertex_type: VertexType::Single1,
150            vertex_usage: VertexUsage::Position,
151            usage_index: 0,
152        }
153        .write_options(writer, endian, ())?;
154
155        let to_seek = (NUM_VERTICES as usize - 1 - declaration.elements.len()) * 8;
156        writer.seek(SeekFrom::Current(to_seek as i64))?;
157    }
158
159    Ok(())
160}