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
// SPDX-License-Identifier: Apache-2.0
//! Source tessellation retained alongside exact boundary representation.
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::assets::AssetId;
use crate::ids::{BodyId, FaceId};
use crate::math::{Point3, Vector3};
use crate::provenance::SourceObjectAssociation;
/// One indexed triangle mesh decoded from a source display or facet stream.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct Tessellation {
/// Stable source-derived identifier.
pub id: String,
/// Body represented by this mesh, when known.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub body: Option<BodyId>,
/// Faces represented by this mesh, empty when face-level ownership is unknown.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub faces: Vec<FaceId>,
/// Source chordal deflection tolerance, when carried.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub chordal_deflection: Option<f64>,
/// Native source-object identity and effective display metadata.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_object: Option<SourceObjectAssociation>,
/// Vertex positions in document units.
pub vertices: Vec<Point3>,
/// Zero-based vertex indices, with source winding preserved.
pub triangles: Vec<[u32; 3]>,
/// Undirected geometric feature edges, as a lexicographically sorted list
/// of unique ascending pairs of zero-based vertex indices. The list
/// excludes ordinary triangulation edges unless the source classifies them
/// as features.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub feature_edges: Vec<[u32; 2]>,
/// Triangle-strip run lengths, when the source stored strips instead of an
/// independent triangle list; empty when the mesh is a flat triangle list.
#[serde(default)]
pub strip_lengths: Vec<u32>,
/// Per-vertex normals, parallel to `vertices`; empty when the source carried none.
#[serde(default)]
pub normals: Vec<Vector3>,
/// Per-triangle-corner normals in flattened `triangles` order. These values
/// preserve normal seams that cannot be represented by `normals` without
/// duplicating vertices.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub corner_normals: Vec<Vector3>,
/// Source face or region groups as an ordered partition of the triangle
/// ordinals. Empty when the source carries no group partition.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub triangle_groups: Vec<TessellationTriangleGroup>,
/// Source texture resources and assets assigned to disjoint sets of
/// triangle ordinals. Omitted triangles have no direct texture assignment.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub texture_assignments: Vec<TessellationTextureAssignment>,
/// Additional per-vertex or per-facet data channels from the source tessellation
/// table (e.g. UVs, colors); empty when the source carried none.
#[serde(default)]
pub channels: Vec<TessellationChannel>,
}
/// One source-defined group in a tessellation triangle partition.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct TessellationTriangleGroup {
/// Source group identity, when the source stores one.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_id: Option<String>,
/// Strictly increasing triangle ordinals belonging to this group.
pub triangles: Vec<u32>,
}
/// One source texture resource assigned directly to tessellation triangles.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct TessellationTextureAssignment {
/// Source texture-resource identity, when the source stores one.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_id: Option<String>,
/// Assigned texture asset.
pub texture: AssetId,
/// Strictly increasing triangle ordinals receiving the texture.
pub triangles: Vec<u32>,
}
/// The mesh element addressed by one tessellation channel.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum TessellationChannelDomain {
/// One channel value is associated with each tessellation vertex.
#[default]
Vertex,
/// Each triangle corner selects one value from the channel table.
Corner,
/// Each triangle selects one value from the channel table.
Triangle,
}
impl TessellationChannelDomain {
#[allow(
clippy::trivially_copy_pass_by_ref,
reason = "Serde skip_serializing_if requires a reference predicate."
)]
fn is_vertex(&self) -> bool {
matches!(self, Self::Vertex)
}
}
/// One descriptor from the source tessellation table.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct TessellationChannel {
/// The mesh element addressed by this channel. Omitted JSON fields use
/// [`TessellationChannelDomain::Vertex`] for compatibility with IR v5.
#[serde(default, skip_serializing_if = "TessellationChannelDomain::is_vertex")]
pub domain: TessellationChannelDomain,
/// Byte size of one element of `data`.
pub item_size: u32,
/// Source channel-kind tag (e.g. UV, color); interpretation is source-defined.
pub kind: u32,
/// Source per-channel flag word.
pub flags: u32,
/// Number of elements in `data`.
pub count: u32,
/// Raw channel payload, `count * item_size` bytes, undecoded.
#[serde(with = "crate::bytes")]
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub data: Vec<u8>,
/// For corner and triangle channels, one selector per addressed mesh
/// element. An empty vector means that a vertex channel uses its implicit
/// vertex-order addressing.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub indices: Vec<u32>,
}