ifc_lite_geometry/instancing/
wire.rs1use super::collate::{collate_refs, Collated, InstanceMeshRef};
6use crate::mesh::Mesh;
7
8pub const INSTANCED_MAGIC: u32 = 0x4946_4E53;
32pub const INSTANCED_VERSION: u32 = 1;
34
35const INST_IDENTITY_F32: [f32; 16] = [
36 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
37];
38
39#[derive(Debug, Clone)]
41pub struct DecodedTemplate {
42 pub positions: Vec<f32>,
43 pub normals: Vec<f32>,
44 pub indices: Vec<u32>,
45 pub origin: [f64; 3],
47}
48
49#[derive(Debug, Clone)]
51pub struct DecodedInstance {
52 pub template_index: u32,
53 pub entity_id: u32,
54 pub color: [f32; 4],
55 pub transform: [f32; 16],
57}
58
59#[derive(Debug, Clone, Default)]
61pub struct DecodedInstanced {
62 pub templates: Vec<DecodedTemplate>,
63 pub instances: Vec<DecodedInstance>,
64}
65
66pub fn encode_refs(meshes: &[InstanceMeshRef], collated: &Collated) -> Vec<u8> {
69 struct TSpec {
71 mesh_idx: usize,
72 instances: Vec<(usize, [f32; 16])>,
73 }
74 let mut tspecs: Vec<TSpec> = Vec::with_capacity(collated.templates.len() + collated.flat_indices.len());
75 for t in &collated.templates {
76 tspecs.push(TSpec {
77 mesh_idx: t.template_index,
78 instances: t.occurrences.iter().map(|o| (o.mesh_index, o.transform)).collect(),
79 });
80 }
81 for &f in &collated.flat_indices {
82 tspecs.push(TSpec {
83 mesh_idx: f,
84 instances: vec![(f, INST_IDENTITY_F32)],
85 });
86 }
87
88 let template_count = tspecs.len();
89 let instance_count: usize = tspecs.iter().map(|t| t.instances.len()).sum();
90 let positions_len: usize = tspecs.iter().map(|t| meshes[t.mesh_idx].positions.len()).sum();
91 let normals_len: usize = tspecs.iter().map(|t| meshes[t.mesh_idx].normals.len()).sum();
92 let indices_len: usize = tspecs.iter().map(|t| meshes[t.mesh_idx].indices.len()).sum();
93
94 assert!(
100 positions_len <= u32::MAX as usize
101 && normals_len <= u32::MAX as usize
102 && indices_len <= u32::MAX as usize
103 && template_count <= u32::MAX as usize
104 && instance_count <= u32::MAX as usize,
105 "instanced shard exceeds u32 wire limits (pos={positions_len} idx={indices_len}); chunk it"
106 );
107
108 let mut buf: Vec<u8> = Vec::with_capacity(
109 32 + template_count * 48 + instance_count * 88 + (positions_len + normals_len + indices_len) * 4,
110 );
111 let pu32 = |b: &mut Vec<u8>, v: u32| b.extend_from_slice(&v.to_le_bytes());
112 let pf32 = |b: &mut Vec<u8>, v: f32| b.extend_from_slice(&v.to_le_bytes());
113 let pf64 = |b: &mut Vec<u8>, v: f64| b.extend_from_slice(&v.to_le_bytes());
114
115 pu32(&mut buf, INSTANCED_MAGIC);
117 pu32(&mut buf, INSTANCED_VERSION);
118 pu32(&mut buf, template_count as u32);
119 pu32(&mut buf, instance_count as u32);
120 pu32(&mut buf, positions_len as u32);
121 pu32(&mut buf, normals_len as u32);
122 pu32(&mut buf, indices_len as u32);
123 pu32(&mut buf, 0);
124
125 let (mut pos_off, mut nrm_off, mut idx_off) = (0u32, 0u32, 0u32);
127 for t in &tspecs {
128 let m = &meshes[t.mesh_idx];
129 pu32(&mut buf, pos_off);
130 pu32(&mut buf, m.positions.len() as u32);
131 pu32(&mut buf, nrm_off);
132 pu32(&mut buf, m.normals.len() as u32);
133 pu32(&mut buf, idx_off);
134 pu32(&mut buf, m.indices.len() as u32);
135 pf64(&mut buf, m.origin[0]);
136 pf64(&mut buf, m.origin[1]);
137 pf64(&mut buf, m.origin[2]);
138 pos_off += m.positions.len() as u32;
139 nrm_off += m.normals.len() as u32;
140 idx_off += m.indices.len() as u32;
141 }
142
143 for (ti, t) in tspecs.iter().enumerate() {
145 for (occ_idx, transform) in &t.instances {
146 pu32(&mut buf, ti as u32);
147 pu32(&mut buf, meshes[*occ_idx].entity_id);
148 for c in meshes[*occ_idx].color {
149 pf32(&mut buf, c);
150 }
151 for v in transform {
152 pf32(&mut buf, *v);
153 }
154 }
155 }
156
157 for t in &tspecs {
159 for &p in meshes[t.mesh_idx].positions {
160 pf32(&mut buf, p);
161 }
162 }
163 for t in &tspecs {
164 for &n in meshes[t.mesh_idx].normals {
165 pf32(&mut buf, n);
166 }
167 }
168 for t in &tspecs {
169 for &i in meshes[t.mesh_idx].indices {
170 pu32(&mut buf, i);
171 }
172 }
173 buf
174}
175
176pub fn encode_instanced(
179 meshes: &[Mesh],
180 collated: &Collated,
181 entity_id: impl Fn(usize) -> u32,
182 color: impl Fn(usize) -> [f32; 4],
183) -> Vec<u8> {
184 let refs: Vec<InstanceMeshRef> = meshes
185 .iter()
186 .enumerate()
187 .map(|(i, m)| {
188 let mut r = InstanceMeshRef::from_mesh(m);
189 r.entity_id = entity_id(i);
190 r.color = color(i);
191 r
192 })
193 .collect();
194 encode_refs(&refs, collated)
195}
196
197pub fn collate_and_encode(meshes: &[InstanceMeshRef], min_group: usize, rtc: [f64; 3]) -> Vec<u8> {
201 let collated = collate_refs(meshes, min_group, rtc);
202 encode_refs(meshes, &collated)
203}
204
205pub fn decode_instanced(bytes: &[u8]) -> Option<DecodedInstanced> {
207 let ru32 = |o: usize| -> Option<u32> {
208 bytes.get(o..o + 4).map(|s| u32::from_le_bytes(s.try_into().unwrap()))
209 };
210 let rf32 = |o: usize| -> Option<f32> {
211 bytes.get(o..o + 4).map(|s| f32::from_le_bytes(s.try_into().unwrap()))
212 };
213 let rf64 = |o: usize| -> Option<f64> {
214 bytes.get(o..o + 8).map(|s| f64::from_le_bytes(s.try_into().unwrap()))
215 };
216 if ru32(0)? != INSTANCED_MAGIC || ru32(4)? != INSTANCED_VERSION {
217 return None;
218 }
219 let template_count = ru32(8)? as usize;
220 let instance_count = ru32(12)? as usize;
221 let positions_len = ru32(16)? as usize;
222 let normals_len = ru32(20)? as usize;
223 let _indices_len = ru32(24)? as usize;
224
225 let tt_off = 32;
226 let it_off = tt_off + template_count * 48;
227 let data_off = it_off + instance_count * 88;
228 let nrm_data = data_off + positions_len * 4;
229 let idx_data = nrm_data + normals_len * 4;
230
231 if bytes.len() < data_off {
238 return None;
239 }
240
241 let mut templates = Vec::with_capacity(template_count);
242 for t in 0..template_count {
243 let r = tt_off + t * 48;
244 let pos_off = ru32(r)? as usize;
245 let pos_len = ru32(r + 4)? as usize;
246 let nrm_off = ru32(r + 8)? as usize;
247 let nrm_len = ru32(r + 12)? as usize;
248 let i_off = ru32(r + 16)? as usize;
249 let i_len = ru32(r + 20)? as usize;
250 let origin = [rf64(r + 24)?, rf64(r + 32)?, rf64(r + 40)?];
251 let positions = (0..pos_len)
252 .map(|k| rf32(data_off + (pos_off + k) * 4))
253 .collect::<Option<Vec<f32>>>()?;
254 let normals = (0..nrm_len)
255 .map(|k| rf32(nrm_data + (nrm_off + k) * 4))
256 .collect::<Option<Vec<f32>>>()?;
257 let indices = (0..i_len)
258 .map(|k| ru32(idx_data + (i_off + k) * 4))
259 .collect::<Option<Vec<u32>>>()?;
260 templates.push(DecodedTemplate { positions, normals, indices, origin });
261 }
262
263 let mut instances = Vec::with_capacity(instance_count);
264 for i in 0..instance_count {
265 let r = it_off + i * 88;
266 let template_index = ru32(r)?;
267 let entity_id = ru32(r + 4)?;
268 let mut color = [0.0f32; 4];
269 for (k, c) in color.iter_mut().enumerate() {
270 *c = rf32(r + 8 + k * 4)?;
271 }
272 let mut transform = [0.0f32; 16];
273 for (k, v) in transform.iter_mut().enumerate() {
274 *v = rf32(r + 24 + k * 4)?;
275 }
276 instances.push(DecodedInstance { template_index, entity_id, color, transform });
277 }
278 Some(DecodedInstanced { templates, instances })
279}