Skip to content

Releases: fernandotonon/QtMeshEditor

2.33.0

30 Apr 17:18
fa71a14

Choose a tag to compare

Highlights

This release wraps up the quad-mesh epic (#326) with end-to-end n-gon preservation through FBX and OBJ I/O, plus a final bug-fix sweep from the chunk merge review.

✨ Features

N-gon export (chunk 6 — #349)

Quad and n-gon meshes now survive a full import → edit → export → re-import round trip on FBX and OBJ:

  • Custom binary FBX writer emits PolygonVertexIndex with the FBX last-index-bitwise-NOT polygon-end convention.
  • Assimp-based OBJ exporter emits aiFace with N indices (>3 vertices).
  • Per-submesh n-gon faces stash on the live Ogre::Mesh::UserObjectBindings (qtme.faces.<i>) so they survive across edit-mode commits, even after qtme.source_path is cleared.
  • Edit-mode re-entry rehydrates EditableSubMesh::faces from the binding so post-edit n-gon ops keep working.

Format support matrix

Format Preserves n-gons? Why
FBX ✅ Yes Custom binary writer
OBJ ✅ Yes Assimp respects aiFace arity
glTF / GLB ❌ No Spec only allows TRIANGLES — preserving quads requires FB_ngon_encoding (vendor extension), out of scope
Ogre .mesh ❌ No Format only stores triangle index buffers
Collada / 3DS / STL / PLY / X ❌ No Assimp writers triangulate

Vertex paint UX (#351)

QML falloff slider + vertex color preview toggle for the brush tool.

🐛 Bug fixes (#352 — sweep from PR #347 review)

8 fixes from CodeRabbit / Codex follow-up:

  • Loop cut rejects mixed quad/tri adjacency upfront (was producing one-sided cuts on the quad side). +1 unit test.
  • Wireframe on tri-only submeshes inside mixed meshes now coexists with the n-gon boundary overlay (was disappearing entirely).
  • buildSubMeshBuffers explicitly clears the GPU vertex/index buffers when a submesh has no triangles to draw (fixes stale geometry rendering after deleting the last face).
  • selectedFacesAsHEFaceIndices now compacts invalid-face indices in the per-face mapping (was silently mis-targeting face-mode ops when invalid faces shifted later HE-face indices).
  • canConvertToQuads() predicate replaces the previous !isMeshQuadBased() check on the toolbar (mixed meshes no longer wrongly disable the action).
  • convertToQuads correctly returns non-zero on promote-only runs.
  • deselectFace mirrors selectFace's vertex/edge dilation (no more stuck partial selections after ctrl-deselect).
  • Test fixture uses a real translate instead of Vector3::ZERO so the assertion stays meaningful if zero-delta short-circuit is ever added.

Two items from the sweep tracked for future work: vertex knife OnVertex near-duplicate, subdivideFacesToQuads T-junctions on partial selections.

🔧 Internal

  • CI test build cache (#348): ccache layered on the SonarCloud build-wrapper. unit-tests-linux job dropped from ~25 min to ~7 min on warm cache (97.88% hit rate observed).

Preview

image

2.32.0

29 Apr 16:38
9e970b3

Choose a tag to compare

Highlights

  • Add vertex paint tool in Edit Mode toolbar (after Fill) with brush settings menu (color, radius, strength).
  • Fix vertex color packing/unpacking to ensure correct RGB rendering across render systems/platforms.
  • Add projected brush ring preview that updates on hover for more precise feedback.
  • Improve paint UX (tool exclusivity, cursor behavior) and add Sentry breadcrumbs for paint actions.

Tests

  • Expanded unit test coverage for vertex paint color parsing and vertex color round-trip behavior.

Preview

image

2.31.0

28 Apr 12:59
db45d44

Choose a tag to compare

Highlights

Edit Mode: new topology operations (Phase 4)

  • Merge Vertices: merge at center/first/last, plus merge-by-distance (shortcut: M).
  • Delete / Dissolve: delete selection with X; dissolve with Ctrl/Cmd+X (keeps the surrounding region watertight).
  • Subdivide / Fill: subdivide selected faces/edges; fill selected vertices or closed edge loops. In Edit Mode, F fills when possible, otherwise it falls back to Frame Selection.

Scan/CLI: more robust scan --fix + better reporting

  • Fixes crashes in the FBX redundant-keyframe fix path (safer material handling, better headless Ogre initialization, empty-track guard).
  • Prevents “fixes” that would increase file size: if output is larger it’s reported as [skipped] and the original file is kept.
  • Improved scan output/summary with [fixed] / [skipped] tags, plus totals for bytes saved and keys removed.
  • Redundant keyframe detection default threshold set to 40%.

Viewport defaults

  • FSAA/MSAA now defaults to 0 when unset (users can opt in via settings). This avoids black viewport issues on some Linux installs.

Web

  • Bumped postcss to 8.5.12 (security + fixes).

Preview

image

Notable PRs

  • #325 Fix scan --fix stability + reporting, default FSAA=0 when unset
  • #324 Subdivide + Fill tools
  • #323 Delete + Dissolve tools
  • #312 Merge Vertices tools
  • #322 postcss bump

2.30.0

26 Apr 23:13
ba60ae4

Choose a tag to compare

Highlights

🎞️ Tolerance-based animation simplifier (#310)

A new operation that removes redundant keyframes whose values match the lerp/slerp of their neighbors within tolerance. First/last keys and sharp pose changes are preserved, so Mixamo-style baked clips shed 40–60% of keys without visible drift.

Surfaced everywhere:

  • CLI: qtmesh anim file.fbx --simplify | --analyze, with --preset {conservative|balanced|aggressive} plus per-axis --tolerance and --rotation-tolerance-deg overrides.
  • Scan rule redundant_keyframes_pct: warns when projected savings exceed a threshold; reports "X% redundant keyframes (N/M). Simplify it to save ~Y. Original size: A, projected size: B".
  • MCP tools simplify_animation + analyze_animation (preset + per-axis overrides).
  • Inspector: per-animation Simplify button (✂) plus a per-entity tolerance preset selector. Tooltip previews redundancy % under the current preset.

The default preset is Balanced (~1mm translation, 0.5° rotation). On a Mixamo Rumba Dancing FBX (1.89 MB):

  • Conservative: 7.9% redundant
  • Balanced: 42.1% redundant
  • Aggressive: 63.8% redundant

📦 FBX exports embed textures (#311)

FBX outputs now embed texture data inline via Video.Content, producing a single self-contained file. No more sidecar .material scripts or extracted texture images alongside the .fbx — the Mixamo-style portable export experience now works out of the box.

Other changes

  • MCP SERVER_VERSION bumped to 1.4.0 (new tools).
  • New shared AnimationMerger::tolerancesForPreset so CLI/MCP/Inspector share the preset table.
  • ThemedComboBox now uses ThemeManager so it works in any panel; aliased into the inspector resource prefix.

What's Changed

Preview

image image

Full Changelog: 2.29.0...2.30.0

2.29.0

25 Apr 03:02
18428e7

Choose a tag to compare

Highlights

  • Knife tool: multi-point cuts with live preview.
  • Bevel Vertex: rounded corner cuts with segment/profile control.
  • Antialias options in the preferences.
  • .vrm file support

Fixes

  • qtmesh scan: correctly handles animation-only FBX (no more false load errors from Assimp 'incomplete' scenes).
  • Import: treat .vrm as supported mesh format (Assimp glTF2 path).

2.28.2

23 Apr 12:46
2dad59b

Choose a tag to compare

Highlights

Bevel — Concave/Convex profiles now carve into adjacent faces (#301)

Previously the bevel's profile graph only shaped the chamfer strip itself — the faces perpendicular to the beveled edge (the "adjacent" faces the bevel cuts corners from) kept a straight diagonal cut, hiding the profile from most camera angles. With this release the adjacent faces follow the chamfer curve too, so concave profiles actually carve a groove through the cube and convex profiles form a rounded fillet — from every angle.

Under the hood:

  • Chain intermediates are now built before the neighbor-face retriangulation, so both code paths can splice them into the cut polyline.
  • A new ear-clipping helper handles the resulting concave polygons correctly (a plain fan would emit a straight diagonal across the arc).
  • Insertion direction on each endpoint is chosen so chain edges pair opposite to the chamfer strip's emissions, keeping the mesh manifold.
  • Endpoint corner caps are skipped for shaped profiles when the neighbor splice already closes the chamfer's end; a chain-polyline cap is emitted instead when no neighbor coverage is available (e.g., boundary endpoints, smooth meshes).

Tests

Four new unit tests cover:

  • Adjacent faces reference the strict chain-interior intermediates for concave profiles.
  • Same for convex profiles.
  • Original corner vertex is unreferenced when shaped (cap skip).
  • Flat chamfer remains manifold — regression guard for the cap-skip change.

Preview

image

2.28.1

22 Apr 16:00
2d06947

Choose a tag to compare

Highlights

Bevel — Segments + Profile (#298)

New bevel-session controls that appear while a bevel is active (between Cmd+B/Ctrl+B and the commit/cancel click):

  • Segments spinbox (1–16): subdivide the chamfer strip into N quads along the profile curve. A single-segment bevel is the classic flat chamfer; raising the count lets you shape the transition.
  • 2D Profile graph: a draggable graph control replaces the old profile slider. For N segments you get N-1 interior control points, one per chord intermediate. Drag a point vertically to bulge that slice outward (convex, toward the original sharp edge) or inward (concave, into the solid). Double-click the graph to reset to a flat chamfer. The graph only appears when segments > 1 — a single-segment bevel has no interior points to shape.

The underlying HalfEdgeMesh::bevelEdges API now accepts an optional per-segment profilePoints vector for direct control; when omitted, the existing profile scalar drives a sin-envelope curve for backwards-compatible single-number control. All 30+ existing bevel tests pass unchanged, and 15 new tests cover the vector overload and the per-segment Qt API end-to-end.

Under the hood

  • EditModeController exposes bevelSessionActiveValue, bevelSegmentsValue, and bevelProfilePointsList as Q_PROPERTY (with NOTIFY bevelProfilePointsChanged) so QML bindings receive live values, not method references. Fixes the silent-binding bug where session-aware UI rendered with stale state.
  • Resizing the segment count now resamples the existing profile points linearly onto the new resolution, preserving the shape the user drew instead of resetting to flat.
  • Test fixture uses unique mesh names per test + removes the mesh in TearDown, so the new E2E tests don't trip Ogre's resource-manager "already exists" exception on rerun.

Preview

image

2.28.0

20 Apr 23:15
9503f72

Choose a tag to compare

Highlights

Phase 4 — Bevel Edges (#295)

  • Interactive edge bevel tool with Cmd+B (macOS) / Ctrl+B (Windows/Linux), multi-face corner fan, chamfer-end cap tracking, and a symmetric offset scaffold.
  • New BevelGizmo for interactive width drag.
  • Post-pass hole filler: scans for bevel-introduced boundary loops in a zone around new offset vertices and bevel-touched verts, fan-triangulates closed loops, and uses geometry-first winding (alignment with neighbor triangles).
  • Repair zone is expanded by position-coincident duplicates so cross-submesh seam cracks can close on multi-submesh character meshes.
  • Walker recovers outer loops after sub-loop extraction at figure-8 junctions and salvages open walks whose endpoints are position-coincident (submesh-seam closure).
  • 65 HalfEdge/bevel unit tests — including 30 random smooth-fan variants and multiple character-bevel fixtures — pass on every platform.

macOS Homebrew bundle (#296)

  • Fixes plugin "qtquickcontrols2plugin" not found on the installed Homebrew bundle. Root cause: QML plugin dylibs kept their Qt-SDK rpath @loader_path/../../../lib which resolves to a nonexistent path inside a .app bundle. CI now adds @executable_path/../Frameworks to every plugin dylib under Contents/PlugIns/qml/ after macdeployqt runs so plugin framework dependencies resolve at runtime.

WinGet publishing (#293)

  • Switched release automation from manual git push to wingetcreate --submit, which uses the Contents API (only public_repo PAT scope) instead of the git database API.

Transform / gizmo fixes bundled in #295

  • Sub-entity scale path no longer compounds across mouse-move events (mirrors the existing entity undo-previous-factor pattern).
  • Edit-mode TS_SCALE now honors snap (matches object-mode).
  • After snapScale, per-component clamp to 0.01 so snapping a near-min delta can't collapse geometry.
  • OgreWidget gates per-frame gizmo scaling to the active viewport (fixes multi-viewport last-listener-wins).
  • scaleFromSnapshot computes soft-selection weights from press-time snapshot positions so vertices near the radius boundary can't drift out of the soft zone mid-drag.

Misc

  • EditModeController destructor no longer propagates exceptions (SonarCloud S1048).
  • isManifold() test helper now rejects same-direction shared edges, matching its documented invariant.
  • Cube-perimeter bevel sweep now fails on rejected bevels instead of silently skipping.

Known limitation

Some bevels on curved multi-submesh character meshes (e.g., Mixamo Lead Jab) still produce small sliver holes that are neither closed loops nor seam cracks. Closing those requires preserving source-file quad topology through the import pipeline and running the bevel on logical quads — a larger refactor deferred to a follow-up.

Preview

image image

2.27.1

17 Apr 16:45
71e279e

Choose a tag to compare

macOS packaging fix

This is a macOS-only patch release. Installed bundles from 2.20 onward shipped with incomplete QML module support, causing the right-side Inspector panel to render blank and the Material editor list to fail to open on Homebrew-installed copies. Source builds were unaffected.

Fix

  • CI now runs macdeployqt on the macOS app bundle after the manual framework copy. macdeployqt scans the bundled QML for imports and pulls in the missing module plugins (QtQuick.Controls, QtQuick.Layouts, QtQuick.Dialogs, QtQuick.Effects, QtQuick.Templates, QtQuick.NativeStyle, …) plus their backing frameworks.
  • Step now fails the job on macdeployqt error instead of swallowing the exit code.
  • Existing install_name_tool -add_rpath calls are now idempotent so they don't collide with rpaths macdeployqt already set.

Upgrade

  • Homebrew: brew upgrade --cask qtmesheditor
  • WinGet / Linux / Windows bundles unchanged from 2.27.0 — no functional change on those platforms.

2.27.0

17 Apr 07:56
3d629f4

Choose a tag to compare

Phase 4: Extrude

New mesh editing operation: Extrude faces in Edit Mode.

Features

  • Extrude works in Face selection mode for both static and skeletal meshes
  • Cmd+E (macOS) / Ctrl+E (Linux/Windows) keyboard shortcut, or click the Extrude button in the Inspector panel
  • Full undo/redo support
  • Preserves textures, normals, tangents (bump maps), bone weights, and animations through the topology change
  • New vertices are offset 0.01 along the face normal so the extruded face is immediately visible — drag with W to translate

Bonus

  • Fixed WinGet CI publishing: releases 2.21–2.26.3 silently failed to publish to microsoft/winget-pkgs (403 Permission denied on git push). Fixed with token-embedded URL.

Internal

  • New HalfEdgeMesh data structure powering topology operations (45 unit tests)
  • Refactored helpers in HalfEdgeMesh and EditableMesh remove ~285 lines of duplicated buffer / edge-rebuild code

Known limitations

  • Edge / vertex extrude not yet wired up (face only for now)

Preview

image