Skip to content

Add global undo/redo system with CDC deduplication (Ctrl+Z / Ctrl+Y)#1641

Open
Z3roCo0l wants to merge 7 commits intocnr-isti-vclab:develfrom
Z3roCo0l:undo-redo
Open

Add global undo/redo system with CDC deduplication (Ctrl+Z / Ctrl+Y)#1641
Z3roCo0l wants to merge 7 commits intocnr-isti-vclab:develfrom
Z3roCo0l:undo-redo

Conversation

@Z3roCo0l
Copy link

Summary

MeshLab has no built-in undo system (see #376). This adds a practical, constrained undo/redo mechanism that works across all filters and edit tools without refactoring MeshLab's internal architecture.

  • Ctrl+Z / Ctrl+Y — undo / redo
  • Available in the Edit menu
  • Supports up to 50 undo levels
  • Covers all filter operations and the Lasso Cut tool

Design Approach

This is intentionally not a full architecture-level undo framework. Instead, it takes mesh state snapshots at well-defined operation boundaries (before each filter execution and before lasso cut operations). The approach coexists with the current architecture without modifying action dispatch, state management, or plugin interfaces.

CDC (Content-Defined Chunking) Deduplication

To make 50 undo levels practical, the system uses content-defined chunking instead of storing full mesh copies:

  1. Serialize — mesh data (vertices, faces, OCF attributes) → deterministic byte buffer (no pointers, compacted indices)
  2. Chunk — Gear hash rolling function splits buffer at content-dependent ~4KB boundaries
  3. Deduplicate — FNV-1a hash identifies identical chunks; shared reference-counted ChunkStore avoids duplication
Full mesh copy CDC dedup
10 undo levels (1M vert mesh) ~920 MB ~93 MB
50 undo levels (1M vert mesh) N/A ~130 MB

Serialization

The serializer handles all CMeshO components:

  • Vertex core: coords, normals, color, quality, flags
  • Face core: vertex indices (compacted), normals, flags
  • OCF attributes: mark, texcoord, curvature direction, radius, quality, color, wedge texcoords
  • Adjacency (VF/FF) is not serialized — rebuilt via UpdateTopology on restore
  • Camera shot, transformation matrix, bounding box, texture strings

Limitations

  • Snapshot-based: captures full mesh state, not individual operations
  • Custom per-vertex/per-face attributes (PointerToAttribute) are not serialized (uncommon in standard workflows)
  • No per-layer undo — operates on the current mesh only

Files Changed

  • src/meshlab/mesh_undo_stack.h — Complete undo system (CDC pipeline + MeshUndoStack class, ~870 lines, all in single header)
  • src/meshlab/mainwindow.h — Undo stack member, Ctrl+Z/Y actions, slots
  • src/meshlab/mainwindow_Init.cpp — Menu entries, keyboard shortcuts
  • src/meshlab/mainwindow_RunTime.cpp — Pre-filter snapshot hook, undo/redo implementation
  • src/meshlabplugins/edit_cut/edit_cut.cpp — Pre-cut snapshot via QMetaObject::invokeMethod (no linker dependency on meshlab.exe)

Test plan

  • Open mesh, apply Laplacian smooth, Ctrl+Z — mesh restores
  • Ctrl+Y — redo works
  • Use lasso cut (Q), Ctrl+Z — mesh restores with correct topology
  • Perform 55 operations, verify oldest undo is dropped (50 level cap)
  • Monitor memory with multiple undo levels — should be ~85-90% less than full copies
  • Build on Windows, Linux, macOS

Note: This is PR 3 of 3 (split from #1638). Depends on #1639 (global params) and #1640 (lasso cut).

Z3roCo0l and others added 7 commits February 12, 2026 10:36
…eload confirmations

- EditPlugin base class: initGlobalParameterList + setCurrentGlobalParamSet
  for persistent per-plugin settings
- edit_select: opt-in "Invert CTRL Behavior" parameter (default OFF)
- Reload/Reload All confirmation dialogs
- Updated all edit plugin factory headers for new interface
New edit plugin that lets users draw a polyline on screen and cut through
mesh triangles along the path. Splits edges at polyline intersections,
re-triangulates affected faces, then selects/deletes faces inside the
polyline boundary.

Features:
- Polyline drawing with mouse clicks
- Edge splitting at polyline-mesh intersections using SplitTab
- Centroid-based face selection for clean boundary cuts
- Two-phase workflow: Q to select (preview), Enter to delete
- Full edit_select-style keybindings (Q/W/D/A/I)
- GPU buffer refresh after mesh modification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove deleteSelectedFaces from edit_cut and let filter_select's
standard Delete shortcut handle deletion (proper undo/redo support).
Preserve selection across endEdit/Escape so the shortcut works.
Move edit_cut button from Edit toolbar to new Dynart Tools toolbar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip cutLog/cutLogQ calls, LOG_PATH, and windows.h/cstdio includes.
Clean production code ready for release.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full-mesh snapshot undo stack covering all filters and edit_cut.
Uses tri::Append::MeshCopy for deep copies, 10 undo levels max.
Edit menu entries with standard keyboard shortcuts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The undo system now serializes meshes to byte buffers, chunks them
using content-defined boundaries (Gear hash), and deduplicates chunks
in a shared reference-counted store. This reduces memory usage by
~80-90% for typical local edits. Undo limit increased from 10 to 50.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant