box3d_rust/recording/
registry.rs1use crate::compound::{convert_bytes_to_compound, CompoundData};
8use crate::height_field::HeightFieldData;
9use crate::hull::HullData;
10use crate::mesh::MeshData;
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(u32)]
16pub enum GeometryKind {
17 Hull = 0,
18 Mesh = 1,
19 HeightField = 2,
20 Compound = 3,
21}
22
23#[derive(Debug, Clone)]
25pub struct GeometryEntry {
26 pub content_hash: u64,
27 pub id: u32,
28 pub kind: GeometryKind,
29 pub bytes: Vec<u8>,
30 pub hash_next: i32,
32}
33
34#[derive(Debug, Default)]
36pub struct GeometryRegistry {
37 pub entries: Vec<GeometryEntry>,
38 dedup: HashMap<u64, i32>,
40}
41
42impl GeometryRegistry {
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn append(&mut self, kind: GeometryKind, content_hash: u64, bytes: Vec<u8>) -> u32 {
49 let id = self.entries.len() as u32;
50 let hash_next = self.dedup.get(&content_hash).copied().unwrap_or(-1);
51 self.entries.push(GeometryEntry {
52 content_hash,
53 id,
54 kind,
55 bytes,
56 hash_next,
57 });
58 self.dedup.insert(content_hash, id as i32);
59 id
60 }
61
62 pub fn intern(&mut self, kind: GeometryKind, content_hash: u64, bytes: Vec<u8>) -> u32 {
64 if let Some(&head) = self.dedup.get(&content_hash) {
65 let mut idx = head;
66 while idx >= 0 {
67 let e = &self.entries[idx as usize];
68 if e.kind == kind && e.bytes == bytes {
69 return e.id;
70 }
71 idx = e.hash_next;
72 }
73 }
74
75 let id = self.entries.len() as u32;
76 let hash_next = self.dedup.get(&content_hash).copied().unwrap_or(-1);
77 self.entries.push(GeometryEntry {
78 content_hash,
79 id,
80 kind,
81 bytes,
82 hash_next,
83 });
84 self.dedup.insert(content_hash, id as i32);
85 id
86 }
87
88 pub fn intern_hull(&mut self, hull: &HullData) -> u32 {
90 let bytes = hull.to_bytes();
91 let h = hash64_blob(&bytes);
92 self.intern(GeometryKind::Hull, h, bytes)
93 }
94
95 pub fn intern_mesh(&mut self, mesh: &MeshData) -> u32 {
97 let bytes = mesh.to_bytes();
98 let h = hash64_blob(&bytes);
99 self.intern(GeometryKind::Mesh, h, bytes)
100 }
101
102 pub fn intern_height_field(&mut self, hf: &HeightFieldData) -> u32 {
104 let bytes = hf.to_bytes();
105 let h = hash64_blob(&bytes);
106 self.intern(GeometryKind::HeightField, h, bytes)
107 }
108
109 pub fn intern_compound(&mut self, compound: &CompoundData) -> u32 {
111 let bytes = compound.to_bytes();
112 let h = hash64_blob(&bytes);
113 self.intern(GeometryKind::Compound, h, bytes)
114 }
115
116 pub fn to_slots(&self) -> Vec<RegistrySlot> {
118 self.entries
119 .iter()
120 .map(|e| RegistrySlot {
121 kind: e.kind,
122 bytes: e.bytes.clone(),
123 live_compound: None,
124 })
125 .collect()
126 }
127}
128
129#[derive(Debug, Clone)]
131pub struct RegistrySlot {
132 pub kind: GeometryKind,
133 pub bytes: Vec<u8>,
134 pub live_compound: Option<CompoundData>,
136}
137
138impl RegistrySlot {
139 pub fn ensure_compound(&mut self) -> Option<&CompoundData> {
140 if self.live_compound.is_none() {
141 self.live_compound = convert_bytes_to_compound(&self.bytes);
142 }
143 self.live_compound.as_ref()
144 }
145}
146
147pub fn hash64_blob(bytes: &[u8]) -> u64 {
151 let n = bytes.len();
152 let mut h = 0xcbf2_9ce4_8422_2325u64 ^ (n as u32 as u64);
153 const PRIME: u64 = 0x1000_0000_01b3;
154 let mut i = 0;
155 while i + 8 <= n {
156 let mut word_bytes = [0u8; 8];
157 word_bytes.copy_from_slice(&bytes[i..i + 8]);
158 let word = u64::from_le_bytes(word_bytes);
159 h = (h ^ word).wrapping_mul(PRIME);
160 i += 8;
161 }
162 while i < n {
163 h = (h ^ bytes[i] as u64).wrapping_mul(PRIME);
164 i += 1;
165 }
166 h ^= h >> 30;
167 h = h.wrapping_mul(0xbf58_476d_1ce4_e5b9);
168 h ^= h >> 27;
169 h = h.wrapping_mul(0x94d0_49bb_1331_11eb);
170 h ^= h >> 31;
171 h
172}