1use crate::channel::Channel;
2use crate::column::ColumnPatch;
3use crate::{Mesh, Result, StoreError, TriangleId, VertexId};
4
5#[derive(Debug, Clone, Default, PartialEq, Eq)]
7pub struct ChangeSet {
8 pub vertices_added: Vec<VertexId>,
9 pub vertices_removed: Vec<VertexId>,
10 pub vertices_moved: Vec<VertexId>,
14 pub triangles_added: Vec<TriangleId>,
15 pub triangles_removed: Vec<TriangleId>,
16 pub triangles_changed: Vec<TriangleId>,
18 pub channels: Vec<(String, Vec<VertexId>)>,
20 pub channels_toggled: Vec<String>,
25}
26
27impl ChangeSet {
28 pub fn topology_changed(&self) -> bool {
30 !(self.triangles_added.is_empty()
31 && self.triangles_removed.is_empty()
32 && self.triangles_changed.is_empty())
33 }
34
35 pub fn is_empty(&self) -> bool {
36 !self.topology_changed()
37 && self.vertices_added.is_empty()
38 && self.vertices_removed.is_empty()
39 && self.vertices_moved.is_empty()
40 && self.channels.iter().all(|(_, v)| v.is_empty())
41 && self.channels_toggled.is_empty()
42 }
43
44 pub fn merge(&mut self, later: &ChangeSet) {
68 for cs in [&*self, later] {
69 let strictly_sorted = |l: &Vec<u32>| l.windows(2).all(|w| w[0] < w[1]);
70 debug_assert!(
71 strictly_sorted(&cs.vertices_added)
72 && strictly_sorted(&cs.vertices_removed)
73 && strictly_sorted(&cs.vertices_moved)
74 && strictly_sorted(&cs.triangles_added)
75 && strictly_sorted(&cs.triangles_removed)
76 && strictly_sorted(&cs.triangles_changed)
77 && cs.channels.iter().all(|(_, v)| strictly_sorted(v)),
78 "change set lists must be sorted and duplicate-free"
79 );
80 }
81 let (vertices_added, vertices_removed, reborn_v) = merge_slots(
82 &self.vertices_added,
83 &self.vertices_removed,
84 &later.vertices_added,
85 &later.vertices_removed,
86 );
87 let (triangles_added, triangles_removed, reborn_t) = merge_slots(
88 &self.triangles_added,
89 &self.triangles_removed,
90 &later.triangles_added,
91 &later.triangles_removed,
92 );
93 let ended = union(&vertices_added, &vertices_removed);
94 let moved = union(
95 &union(&self.vertices_moved, &later.vertices_moved),
96 &reborn_v,
97 );
98 self.vertices_moved = difference(&moved, &ended);
99 let ended_t = union(&triangles_added, &triangles_removed);
100 let changed = union(
101 &union(&self.triangles_changed, &later.triangles_changed),
102 &reborn_t,
103 );
104 self.triangles_changed = difference(&changed, &ended_t);
105
106 for (name, ids) in &later.channels {
107 match self.channels.iter_mut().find(|(n, _)| n == name) {
108 Some((_, mine)) => *mine = union(mine, ids),
109 None => self.channels.push((name.clone(), ids.clone())),
110 }
111 }
112 for (_, ids) in &mut self.channels {
113 *ids = difference(ids, &ended);
114 }
115 for (_, ids) in &mut self.channels {
116 *ids = union(ids, &reborn_v);
117 }
118
119 for name in &later.channels_toggled {
120 if let Err(at) = self.channels_toggled.binary_search(name) {
121 self.channels_toggled.insert(at, name.clone());
122 }
123 }
124
125 self.vertices_added = vertices_added;
126 self.vertices_removed = vertices_removed;
127 self.triangles_added = triangles_added;
128 self.triangles_removed = triangles_removed;
129 }
130
131 fn inverted(mut self) -> Self {
132 std::mem::swap(&mut self.vertices_added, &mut self.vertices_removed);
133 std::mem::swap(&mut self.triangles_added, &mut self.triangles_removed);
134 self
135 }
136}
137
138fn union(a: &[u32], b: &[u32]) -> Vec<u32> {
140 let mut out = Vec::with_capacity(a.len() + b.len());
141 let (mut i, mut j) = (0, 0);
142 while i < a.len() && j < b.len() {
143 match a[i].cmp(&b[j]) {
144 std::cmp::Ordering::Less => {
145 out.push(a[i]);
146 i += 1;
147 }
148 std::cmp::Ordering::Greater => {
149 out.push(b[j]);
150 j += 1;
151 }
152 std::cmp::Ordering::Equal => {
153 out.push(a[i]);
154 i += 1;
155 j += 1;
156 }
157 }
158 }
159 out.extend_from_slice(&a[i..]);
160 out.extend_from_slice(&b[j..]);
161 out
162}
163
164fn difference(a: &[u32], b: &[u32]) -> Vec<u32> {
166 let mut j = 0;
167 a.iter()
168 .copied()
169 .filter(|&x| {
170 while j < b.len() && b[j] < x {
171 j += 1;
172 }
173 !(j < b.len() && b[j] == x)
174 })
175 .collect()
176}
177
178fn merge_slots(
181 add1: &[u32],
182 rem1: &[u32],
183 add2: &[u32],
184 rem2: &[u32],
185) -> (Vec<u32>, Vec<u32>, Vec<u32>) {
186 let added = union(&difference(add1, rem2), &difference(add2, rem1));
187 let removed = union(&difference(rem1, add2), &difference(rem2, add1));
188 let reborn = difference(rem1, &difference(rem1, add2));
189 (added, removed, reborn)
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194pub enum PatchSide {
195 Undoable,
197 Redoable,
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum PatchState {
205 Applied,
207 Undone,
209}
210
211#[derive(Debug, Clone)]
218pub struct Patch {
219 pub(crate) mesh_uid: u64,
220 pub(crate) epoch: u32,
221 pub(crate) base_revision: u64,
222 pub(crate) revision: u64,
223 pub(crate) positions: ColumnPatch<[f32; 3]>,
224 pub(crate) triangles: ColumnPatch<[u32; 3]>,
225 pub(crate) vertex_live: ColumnPatch<u64>,
226 pub(crate) triangle_live: ColumnPatch<u64>,
227 pub(crate) vertex_refs: ColumnPatch<u32>,
228 pub(crate) channel_data: Vec<(u64, ColumnPatch<f32>)>,
230 pub(crate) dropped_channels: Vec<u64>,
233 pub(crate) dropped_bytes: usize,
235 pub(crate) channels_before: u64,
238 pub(crate) changes: ChangeSet,
239}
240
241impl Patch {
242 pub fn changes(&self) -> &ChangeSet {
244 &self.changes
245 }
246
247 pub fn is_empty(&self) -> bool {
249 self.base_revision == self.revision
250 }
251
252 pub fn base_revision(&self) -> u64 {
254 self.base_revision
255 }
256
257 pub fn revision(&self) -> u64 {
259 self.revision
260 }
261
262 pub fn byte_size(&self) -> usize {
264 let c = &self.changes;
265 let ids = c.vertices_added.len()
266 + c.vertices_removed.len()
267 + c.vertices_moved.len()
268 + c.triangles_added.len()
269 + c.triangles_removed.len()
270 + c.triangles_changed.len()
271 + c.channels.iter().map(|(_, v)| v.len()).sum::<usize>();
272 self.positions.byte_size()
273 + self.triangles.byte_size()
274 + self.vertex_live.byte_size()
275 + self.triangle_live.byte_size()
276 + self.vertex_refs.byte_size()
277 + self
278 .channel_data
279 .iter()
280 .map(|(_, p)| 8 + p.byte_size())
281 .sum::<usize>()
282 + ids * 4
283 + self.dropped_bytes
284 }
285
286 pub fn apply(&self, mesh: &mut Mesh) -> Result<ChangeSet> {
289 self.check(mesh, self.base_revision)?;
290 let vertex_slots = mesh.positions.len().max(self.positions.required_len());
293 mesh.positions
294 .try_reserve_to(self.positions.required_len())?;
295 mesh.triangles
296 .try_reserve_to(self.triangles.required_len())?;
297 mesh.vertex_live
298 .try_reserve_to(self.vertex_live.required_len())?;
299 mesh.triangle_live
300 .try_reserve_to(self.triangle_live.required_len())?;
301 mesh.vertex_refs
302 .try_reserve_to(self.vertex_refs.required_len())?;
303 for c in &mut mesh.channels {
304 c.data.try_reserve_to(self.channel_len(c, vertex_slots))?;
305 }
306
307 mesh.positions
309 .resize_reserved(self.positions.required_len(), [0.0; 3]);
310 mesh.triangles
311 .resize_reserved(self.triangles.required_len(), [0; 3]);
312 mesh.vertex_live
313 .resize_reserved(self.vertex_live.required_len(), 0);
314 mesh.triangle_live
315 .resize_reserved(self.triangle_live.required_len(), 0);
316 mesh.vertex_refs
317 .resize_reserved(self.vertex_refs.required_len(), 0);
318 for c in &mut mesh.channels {
319 let len = self.channel_len(c, vertex_slots);
320 c.data.resize_reserved(len, c.desc.default);
321 }
322
323 self.forget_newer_bound_channels(mesh);
326 let c = &self.changes;
327 let ids = [
328 &c.triangles_added[..],
329 &c.triangles_removed[..],
330 &c.triangles_changed[..],
331 ];
332 mesh.with_incidence(|inc, m| inc.remove_alive(m, &ids));
333 self.positions.apply(&mut mesh.positions);
334 self.triangles.apply(&mut mesh.triangles);
335 self.vertex_live.apply(&mut mesh.vertex_live);
336 self.triangle_live.apply(&mut mesh.triangle_live);
337 self.vertex_refs.apply(&mut mesh.vertex_refs);
338 for (id, p) in &self.channel_data {
339 if let Some(i) = mesh.channel_index_by_id(*id) {
340 p.apply(&mut mesh.channels[i].data);
341 }
342 }
343 for &id in &self.dropped_channels {
344 if let Some(i) = mesh.channel_index_by_id(id) {
345 mesh.channels[i].hidden = true;
346 }
347 }
348 mesh.live_vertices = mesh.live_vertices + c.vertices_added.len() - c.vertices_removed.len();
349 mesh.live_triangles =
350 mesh.live_triangles + c.triangles_added.len() - c.triangles_removed.len();
351 mesh.revision = self.revision;
352 if c.topology_changed() {
353 mesh.adjacency = None;
354 mesh.with_incidence(|inc, m| inc.insert_alive(m, &ids));
355 }
356 Ok(self.changes.clone())
357 }
358
359 fn forget_newer_bound_channels(&self, mesh: &mut Mesh) {
363 mesh.channels
364 .retain(|c| !(c.desc.topology_bound && c.id >= self.channels_before));
365 }
366
367 pub fn revert(&self, mesh: &mut Mesh) -> Result<ChangeSet> {
369 self.check(mesh, self.revision)?;
370 self.forget_newer_bound_channels(mesh);
371 let c = &self.changes;
372 let ids = [
373 &c.triangles_added[..],
374 &c.triangles_removed[..],
375 &c.triangles_changed[..],
376 ];
377 mesh.with_incidence(|inc, m| inc.remove_alive(m, &ids));
378 self.positions.revert(&mut mesh.positions);
379 self.triangles.revert(&mut mesh.triangles);
380 self.vertex_live.revert(&mut mesh.vertex_live);
381 self.triangle_live.revert(&mut mesh.triangle_live);
382 self.vertex_refs.revert(&mut mesh.vertex_refs);
383 for (id, p) in &self.channel_data {
384 if let Some(i) = mesh.channel_index_by_id(*id) {
385 p.revert(&mut mesh.channels[i].data);
386 }
387 }
388 for &id in &self.dropped_channels {
389 if let Some(i) = mesh.channel_index_by_id(id) {
390 let name = mesh.channels[i].desc.name.clone();
392 if let Some(newer) = mesh.channel_index(&name) {
393 mesh.channels.remove(newer);
394 }
395 if let Some(i) = mesh.channel_index_by_id(id) {
396 mesh.channels[i].hidden = false;
397 }
398 }
399 }
400 mesh.live_vertices = mesh.live_vertices + c.vertices_removed.len() - c.vertices_added.len();
401 mesh.live_triangles =
402 mesh.live_triangles + c.triangles_removed.len() - c.triangles_added.len();
403 mesh.revision = self.base_revision;
404 if c.topology_changed() {
405 mesh.adjacency = None;
406 mesh.with_incidence(|inc, m| inc.insert_alive(m, &ids));
407 }
408 Ok(self.changes.clone().inverted())
409 }
410
411 pub fn release(&self, mesh: &mut Mesh, side: PatchSide) {
421 if self.mesh_uid != mesh.uid || self.epoch != mesh.epoch {
422 return;
423 }
424 let c = &self.changes;
425 match side {
426 PatchSide::Undoable => {
427 mesh.release_vertices(&c.vertices_removed);
428 mesh.release_triangles(&c.triangles_removed);
429 mesh.channels
431 .retain(|ch| !(ch.hidden && self.dropped_channels.contains(&ch.id)));
432 }
433 PatchSide::Redoable => {
434 mesh.release_vertices(&c.vertices_added);
435 mesh.release_triangles(&c.triangles_added);
436 }
437 }
438 }
439
440 fn channel_len(&self, c: &Channel, vertex_slots: usize) -> usize {
443 let own = self
444 .channel_data
445 .iter()
446 .find(|(id, _)| *id == c.id)
447 .map_or(0, |(_, p)| p.required_len());
448 own.max(vertex_slots * c.desc.width)
449 }
450
451 fn check(&self, mesh: &Mesh, expected_revision: u64) -> Result<()> {
452 if self.mesh_uid != mesh.uid {
453 return Err(StoreError::PatchMismatch);
454 }
455 if self.epoch != mesh.epoch {
456 return Err(StoreError::StalePatch);
457 }
458 if mesh.revision != expected_revision {
459 return Err(StoreError::PatchMismatch);
460 }
461 Ok(())
462 }
463}
464
465#[cfg(test)]
466mod tests {
467 use crate::column::fail_allocations_after;
468 use crate::{ChangeSet, ChannelDesc, Mesh, PatchSide, StoreError};
469
470 fn quad() -> Mesh {
471 Mesh::from_buffers(
472 &[0., 0., 0., 1., 0., 0., 1., 1., 0., 0., 1., 0.],
473 &[0, 1, 2, 0, 2, 3],
474 )
475 .unwrap()
476 }
477
478 #[test]
479 fn release_matches_history_eviction() {
480 let mut m = quad();
481 let mut tx = m.begin_edit();
482 tx.remove_triangles(&[1]).unwrap();
483 tx.remove_vertices(&[3]).unwrap();
484 let removal = tx.commit().unwrap();
485 assert!(m.free_vertex_slots().is_empty(), "reserved by the patch");
486 removal.release(&mut m, PatchSide::Redoable);
488 assert!(m.free_vertex_slots().is_empty());
489 removal.release(&mut m, PatchSide::Undoable);
490 assert_eq!(m.free_vertex_slots(), &[3]);
491 assert_eq!(m.free_triangle_slots(), &[1]);
492
493 let mut tx = m.begin_edit();
494 tx.add_vertices(&[[0.; 3]]).unwrap();
495 let creation = tx.commit().unwrap();
496 creation.revert(&mut m).unwrap();
497 assert!(m.free_vertex_slots().is_empty(), "reserved for redo");
498 creation.release(&mut m, PatchSide::Redoable);
499 assert_eq!(m.free_vertex_slots(), &[3]);
500 }
501
502 #[test]
503 fn merge_applies_net_effect_rules() {
504 let mut a = ChangeSet {
505 vertices_added: vec![5],
506 vertices_removed: vec![2],
507 vertices_moved: vec![1, 3],
508 triangles_added: vec![4],
509 triangles_removed: vec![0],
510 triangles_changed: vec![1],
511 channels: vec![("c".into(), vec![1, 3])],
512 channels_toggled: vec![],
513 };
514 let b = ChangeSet {
515 vertices_added: vec![2],
516 vertices_removed: vec![3, 5],
517 vertices_moved: vec![1],
518 triangles_added: vec![0],
519 triangles_removed: vec![4],
520 triangles_changed: vec![],
521 channels: vec![("c".into(), vec![0]), ("d".into(), vec![1])],
522 channels_toggled: vec![],
523 };
524 a.merge(&b);
525 assert_eq!(a.vertices_added, Vec::<u32>::new());
526 assert_eq!(a.vertices_removed, vec![3]);
527 assert_eq!(a.vertices_moved, vec![1, 2]);
528 assert_eq!(a.triangles_added, Vec::<u32>::new());
529 assert_eq!(a.triangles_removed, Vec::<u32>::new());
530 assert_eq!(a.triangles_changed, vec![0, 1]);
531 assert_eq!(
532 a.channels,
533 vec![
534 ("c".to_string(), vec![0, 1, 2]),
535 ("d".to_string(), vec![1, 2])
536 ]
537 );
538 }
539
540 fn lengths(m: &Mesh) -> Vec<usize> {
542 let mut l = vec![
543 m.positions.len(),
544 m.vertex_refs.len(),
545 m.vertex_live.len(),
546 m.triangles.len(),
547 m.triangle_live.len(),
548 ];
549 l.extend(m.channels.iter().map(|c| c.data.len()));
550 l
551 }
552
553 #[test]
554 fn apply_that_runs_out_of_memory_leaves_every_column_unchanged() {
555 let mut m = quad();
556 m.add_channel(ChannelDesc::source("c", 2)).unwrap();
557 m.add_channel(ChannelDesc::derived("d", 1)).unwrap();
558 let mut tx = m.begin_edit();
559 let vs = tx.add_vertices(&[[2.; 3]; 70]).unwrap();
561 tx.add_triangles(&[[0, vs[0], vs[1]]]).unwrap();
562 tx.write_channel("c", &[0], &[5., 6.]).unwrap();
563 let patch = tx.commit().unwrap();
564 patch.revert(&mut m).unwrap();
565 m.positions.truncate(4);
567 m.vertex_refs.truncate(4);
568 m.vertex_live.truncate(1);
569 m.triangles.truncate(2);
570 m.triangle_live.truncate(1);
571 for c in &mut m.channels {
572 let w = c.desc.width;
573 c.data.truncate(4 * w);
574 }
575 let before = lengths(&m);
576 let revision = m.revision();
577 for k in 0.. {
578 fail_allocations_after(Some(k));
579 let result = patch.apply(&mut m);
580 fail_allocations_after(None);
581 match result {
582 Err(e) => {
583 assert_eq!(e, StoreError::OutOfMemory);
584 assert_eq!(lengths(&m), before, "failed after {k} allocations");
585 assert_eq!(m.revision(), revision);
586 assert_eq!((m.vertex_count(), m.triangle_count()), (4, 2));
587 }
588 Ok(_) => {
589 assert!(k > 0, "apply needs to allocate");
590 assert_eq!((m.vertex_count(), m.triangle_count()), (74, 3));
591 assert_eq!(lengths(&m), vec![74, 74, 2, 3, 1, 148, 74]);
592 assert_eq!(&m.channel("c").unwrap()[..2], &[5., 6.]);
593 assert_eq!(m.triangle(2), Some([0, vs[0], vs[1]]));
594 break;
595 }
596 }
597 }
598 }
599}