Skip to main content

geometry_dag/
types.rs

1//! 核心常量与数据结构。
2//!
3//! 与 TS 权威实现(`packages/deep-engine/src/geometry/types.ts` + `meshletDag.ts`)
4//! 字段一一对应;`docs/dgc-format-spec.md` 定义这些数组的持久化布局。
5
6/// 簇描述符步长:`[vertexOffset, vertexCount, triangleOffset, triangleCount]`,
7/// 每簇一条 16 字节记录,偏移是元素偏移而非字节偏移。
8pub const MESHLET_DESCRIPTOR_STRIDE: usize = 4;
9
10/// 包围盒步长:`sphere vec4, aabbMin vec4, aabbMax vec4, normalCone vec4`,
11/// 每簇一条 64 字节记录。cone cutoff 为 -1 表示法向锥剔除禁用。
12pub const MESHLET_BOUNDS_STRIDE: usize = 16;
13
14/// 当前 schema 版本(与 TS `MESHLET_SCHEMA_VERSION` 同步)。
15pub const MESHLET_SCHEMA_VERSION: u32 = 1;
16
17/// 簇默认顶点上限(TS `MESHLET_DEFAULTS.maxVertices`)。
18pub const MESHLET_MAX_VERTICES_LIMIT: u32 = 64;
19
20/// 簇默认三角形上限(TS `MESHLET_DEFAULTS.maxTriangles`)。
21pub const MESHLET_MAX_TRIANGLES_LIMIT: u32 = 126;
22
23/// 构建预算:源顶点数上限(TS `MESHLET_BUILD_BUDGETS.sourceVertices`)。
24pub const SOURCE_VERTICES_BUDGET: u64 = 16_777_216;
25
26/// 构建预算:源三角形数上限(TS `MESHLET_BUILD_BUDGETS.sourceTriangles`)。
27pub const SOURCE_TRIANGLES_BUDGET: u64 = 4_000_000;
28
29/// 构建预算:输出簇数上限(TS `MESHLET_BUILD_BUDGETS.outputMeshlets`)。
30pub const OUTPUT_MESHLETS_BUDGET: u64 = 4_000_000;
31
32/// 构建预算:DAG 全层输出三角形总量上限(TS `MeshletDagOptions.outputTriangleBudget` 缺省)。
33pub const OUTPUT_TRIANGLE_BUDGET_DEFAULT: u64 = 8_000_000;
34
35/// 索引化三角形网格输入(位置为紧凑 XYZ,f32)。
36#[derive(Debug, Clone)]
37pub struct IndexedGeometry {
38    /// 紧凑 XYZ 顶点位置,长度为 3 的倍数。
39    pub positions: Vec<f32>,
40    /// 三角形索引,长度为 3 的倍数,取值必须落在顶点范围内。
41    pub indices: Vec<u32>,
42}
43
44impl IndexedGeometry {
45    /// 顶点数(positions 元素数 / 3)。
46    #[must_use]
47    pub fn vertex_count(&self) -> usize {
48        self.positions.len() / 3
49    }
50
51    /// 三角形数(indices 元素数 / 3)。
52    #[must_use]
53    pub fn triangle_count(&self) -> usize {
54        self.indices.len() / 3
55    }
56}
57
58/// 单个簇(贪心装箱结果的一部分):局部顶点表与打包的局部三角形。
59#[derive(Debug, Default)]
60pub(crate) struct PendingMeshlet {
61    /// 全局顶点 → 局部索引。
62    local_by_global: rustc_hash_lite::FxHashMap<u32, u32>,
63    /// 全局顶点表(按首次出现序,与 TS `pending.vertices` 一致)。
64    pub(crate) vertices: Vec<u32>,
65    /// 打包局部三角形(pack_local_triangle 结果)。
66    pub(crate) triangles: Vec<u32>,
67    /// 非退化三角形单位法线(f64 精度,与 TS 一致)。
68    pub(crate) normals: Vec<[f64; 3]>,
69    /// 出现过退化三角形则法向锥禁用。
70    pub(crate) has_degenerate: bool,
71}
72
73impl PendingMeshlet {
74    pub(crate) fn new() -> Self {
75        Self::default()
76    }
77
78    /// 判断全局顶点是否已在当前簇内。
79    #[inline]
80    pub(crate) fn contains_global(&self, global: u32) -> bool {
81        self.local_by_global.contains_key(&global)
82    }
83
84    /// 取全局顶点的局部索引,不存在则追加(首次出现序)。
85    pub(crate) fn local_vertex(&mut self, global: u32) -> u32 {
86        if let Some(&existing) = self.local_by_global.get(&global) {
87            return existing;
88        }
89        let local = self.vertices.len() as u32;
90        self.local_by_global.insert(global, local);
91        self.vertices.push(global);
92        local
93    }
94}
95
96/// 轻量 FxHash 哈希表:避免引入完整 rustc-hash 依赖,同时保持 O(1) 插入查询。
97/// 仅在本 crate 内部使用,键为 u32,无 DoS 放大面。
98pub(crate) mod rustc_hash_lite {
99    /// FxHasher(Browner-speed hash,与 rustc-hash 同族常数)。
100    #[derive(Default)]
101    pub(crate) struct FxHasher(u64);
102
103    impl std::hash::Hasher for FxHasher {
104        #[inline]
105        fn write_u32(&mut self, v: u32) {
106            self.0 = (self.0.rotate_left(5) ^ u64::from(v)).wrapping_mul(0x517c_c1b7_2722_0a95);
107        }
108
109        #[inline]
110        fn write_usize(&mut self, v: usize) {
111            self.write_u64(v as u64);
112        }
113
114        #[inline]
115        fn write_u64(&mut self, v: u64) {
116            self.0 = (self.0.rotate_left(5) ^ v).wrapping_mul(0x517c_c1b7_2722_0a95);
117        }
118
119        #[inline]
120        fn write(&mut self, bytes: &[u8]) {
121            for &b in bytes {
122                self.0 = (self.0.rotate_left(5) ^ u64::from(b)).wrapping_mul(0x517c_c1b7_2722_0a95);
123            }
124        }
125
126        #[inline]
127        fn finish(&self) -> u64 {
128            self.0
129        }
130    }
131
132    /// 以 FxHasher 为后端的 `HashMap` 别名。
133    pub(crate) type FxHashMap<K, V> = std::collections::HashMap<K, V, std::hash::BuildHasherDefault<FxHasher>>;
134
135    /// 以 FxHasher 为后端的 `HashSet` 别名。
136    pub(crate) type FxHashSet<K> = std::collections::HashSet<K, std::hash::BuildHasherDefault<FxHasher>>;
137}