aboutsummaryrefslogtreecommitdiff
path: root/crates/fparkan-msh/src
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-10-30 22:16:31 +0300
committerValentin Popov <valentin@popov.link>2026-10-30 22:16:31 +0300
commit048ad71f5c5c5a21aabb42dad1562b40b7a54ea2 (patch)
tree3b21bb5aeeb4280064fa749ce417067510d32b1c /crates/fparkan-msh/src
parenteaf5df3ad01af591e394ef8f6542dd0b4c98d43b (diff)
downloadfparkan-048ad71f5c5c5a21aabb42dad1562b40b7a54ea2.tar.xz
fparkan-048ad71f5c5c5a21aabb42dad1562b40b7a54ea2.zip
fix(render): hide native zero-alpha MSH batches
Diffstat (limited to 'crates/fparkan-msh/src')
-rw-r--r--crates/fparkan-msh/src/lib.rs31
1 files changed, 31 insertions, 0 deletions
diff --git a/crates/fparkan-msh/src/lib.rs b/crates/fparkan-msh/src/lib.rs
index c35a3dc..3bbe17e 100644
--- a/crates/fparkan-msh/src/lib.rs
+++ b/crates/fparkan-msh/src/lib.rs
@@ -21,6 +21,8 @@ pub const STREAM_UV0: u32 = 5;
/// Optional secondary texture coordinate stream used by native lightmap/detail
/// stages. MSH stores it as the type-18 four-byte packed UV stream.
pub const STREAM_UV1: u32 = 18;
+/// Optional type-16 stream. Its presence marks MSH vertex-colour data.
+pub const STREAM_TYPE_16: u32 = 16;
/// Triangle index stream.
pub const STREAM_INDICES: u32 = 6;
/// Optional triangle-descriptor stream.
@@ -101,6 +103,10 @@ pub struct ModelAsset {
pub uv0: Option<Vec<[u16; 2]>>,
/// Optional secondary packed texture coordinates from type 18.
pub uv1: Option<Vec<[u16; 2]>>,
+ /// Whether the source MSH contains a type-16 vertex-colour stream.
+ ///
+ /// The stream payload is preserved separately and is not decoded here.
+ pub type16_present: bool,
/// Triangle indices.
pub indices: Vec<u16>,
/// Draw batches.
@@ -1116,6 +1122,7 @@ fn parse_model_document(document: &NresDocument) -> Result<ModelAsset, MshError>
let uv1 = read_optional_stream(document, STREAM_UV1)?
.map(|raw| parse_secondary_uv_stream(raw, positions.len()))
.transpose()?;
+ let type16_present = read_optional_stream(document, STREAM_TYPE_16)?.is_some();
let triangle_descriptors = read_optional_triangle_descriptors(document)?
.map(|raw| parse_triangle_descriptors(&raw.bytes))
.transpose()?;
@@ -1135,6 +1142,7 @@ fn parse_model_document(document: &NresDocument) -> Result<ModelAsset, MshError>
normals,
uv0,
uv1,
+ type16_present,
indices,
batches,
triangle_descriptors,
@@ -1641,6 +1649,25 @@ mod tests {
assert_eq!(model.node_count, 0);
assert!(model.slots.is_empty());
assert_eq!(model.triangle_descriptors, None);
+ assert!(!model.type16_present);
+ }
+
+ #[test]
+ fn type16_presence_is_preserved_without_decoding_its_payload() {
+ let payload = [0xDE, 0xAD, 0xBE, 0xEF];
+ let document = decode_nested(&build_nres(&[
+ stream(STREAM_NODE_TABLE, 38, b"Res1", &[]),
+ stream(STREAM_SLOTS, 0, b"Res2", &slots_payload(&[])),
+ stream(STREAM_POSITIONS, 0, b"Res3", &[]),
+ stream(STREAM_INDICES, 0, b"Res6", &[]),
+ stream(STREAM_BATCHES, 0, b"Res13", &[]),
+ stream(STREAM_TYPE_16, 0, b"Res16", &payload),
+ ]))
+ .expect("nested NRes");
+ let model =
+ validate_msh(&decode_msh(&document).expect("MSH document")).expect("model asset");
+
+ assert!(model.type16_present);
}
#[test]
@@ -2262,6 +2289,7 @@ mod tests {
normals: None,
uv0: None,
uv1: None,
+ type16_present: false,
indices: Vec::new(),
batches: Vec::new(),
triangle_descriptors: None,
@@ -2324,6 +2352,7 @@ mod tests {
normals: None,
uv0: None,
uv1: None,
+ type16_present: false,
indices: Vec::new(),
batches: Vec::new(),
triangle_descriptors: None,
@@ -2389,6 +2418,7 @@ mod tests {
normals: None,
uv0: None,
uv1: None,
+ type16_present: false,
indices: Vec::new(),
batches: Vec::new(),
triangle_descriptors: None,
@@ -3282,6 +3312,7 @@ mod tests {
normals: None,
uv0: None,
uv1: None,
+ type16_present: false,
indices,
batches,
node_names: None,