Skip to content

fix(quads): bug-fix sweep from PR #347 review (8 of 10 items) - #352

Merged
fernandotonon merged 1 commit into
masterfrom
fix/quads-bug-sweep
Apr 30, 2026
Merged

fix(quads): bug-fix sweep from PR #347 review (8 of 10 items)#352
fernandotonon merged 1 commit into
masterfrom
fix/quads-bug-sweep

Conversation

@fernandotonon

Copy link
Copy Markdown
Owner

Summary

Addresses the 10 deferred review items from PR #347 epic merge. 8 fixed in this PR, the remaining 2 are heavier lifts tracked for a separate PR.

What's fixed

Major bugs

  • Mac os build #1 Loop cut mixed quad/tri adjacency (Codex P1) — `HalfEdgeMesh::loopCut` walked both sides of the start edge independently, so a quad+tri adjacency produced a one-sided cut on the quad side. Now rejects upfront when either face is non-quad. +1 unit test.
  • Update to build with current version of dependencies and in the 3 main desktop OS #2 Wireframe lost on tri-only submeshes in mixed meshes (Codex P2) — `applyWireframeMaterials` flipped globally to overlay mode if ANY submesh had `.faces`, but the overlay only emits n-gon submeshes. Now per-submesh: PM_WIREFRAME on tri-only, boundary overlay on n-gon, both active simultaneously.
  • pull requests template #3 `buildSubMeshBuffers` stale GPU buffers (CodeRabbit Major) — early-return left vertex/index data attached when a topology op deleted the last face. Now explicitly clears.
  • Build config improvements #4 Compact invalid faces in HE-face mapping (CodeRabbit Major) — `selectedFacesAsHEFaceIndices` only compacted the per-submesh base offset, not the per-face index. An invalid face earlier in `sub.faces` shifted later HE-face indices, mis-targeting face-mode extrude/delete/dissolve/subdivide.
  • Automate deploy  #7 `canConvertToQuads()` predicate (CodeRabbit Major) — `!isMeshQuadBased()` wrongly disabled Convert-to-Quads on mixed meshes (any n-gon submesh present made it false even when tri-only submeshes still had work). New predicate returns true iff at least one submesh still has triangle-only representation.
  • Improve controls using trackpad #8 `convertToQuads` return value (CodeRabbit Minor → bumped to functional) — promote-only runs (no merges, but submesh promoted from tri to n-gon) returned 0, misreporting success as no-op. Now returns merges + promotions.
  • Allow export to different formats using assimp #9 `deselectFace` mirror (CodeRabbit Minor → bumped) — left perimeter vertices/edges in the selection sets after ctrl-deselect, looking like a stuck partial selection. Now mirrors selectFace's dilation.
  • Update and rename cmake.yml to deploy.yml #10 Zero-translate test fixture (CodeRabbit Minor) — replaced `Vector3::ZERO` with `(0.001f, 0, 0)` so commit-path assertion stays meaningful if zero-delta short-circuit is ever added.

Deferred to separate follow-up PR

  • Create build-n-cache-ogre.yml #5 Vertex knife near-duplicate — `OnVertex` clicks become arbitrary near-edge splits via splitEdge clamping. Needs a different splitFace path for true vertex hits.
  • Import .FBX with animation #6 `subdivideFacesToQuads` T-junctions — leaves adjacent unselected faces untouched; partial n-gon selections produce T-junctions. Needs adjacent-face retriangulation pass like the existing tri subdivide.

Test plan

  • All 233 standalone topology + EditableMesh tests pass on macOS
  • +1 new `LoopCutRejectsMixedQuadTriAdjacency` test covers the regression
  • Build clean (full app + UnitTests targets)
  • CI green on Linux (will validate via this PR)

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@fernandotonon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 39 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0254ce29-b722-4c7b-88f0-b34975528abd

📥 Commits

Reviewing files that changed from the base of the PR and between 223191e and f28e7f4.

📒 Files selected for processing (7)
  • src/EditModeController.cpp
  • src/EditModeController.h
  • src/EditModeController_test.cpp
  • src/EditableMesh.cpp
  • src/HalfEdgeMesh.cpp
  • src/HalfEdgeMesh_test.cpp
  • src/mainwindow.cpp
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/quads-bug-sweep

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 31 minutes and 39 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a11e4dd08

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +795 to +797
m_selectedVertices.erase(g0);
m_selectedEdges.erase({std::min(g0, g1), std::max(g0, g1)});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep shared boundary elements selected on face deselect

When two adjacent faces are selected, ctrl-deselecting one face now unconditionally erases all of that face’s vertices/edges from m_selectedVertices and m_selectedEdges, even if those elements are still part of another selected face. This makes edge/vertex overlays and selection counts inconsistent with m_selectedFaces for multi-face selections (e.g., shared edge disappears while the neighboring face remains selected). The deselect path needs to recompute or reference-count shared elements instead of blindly erasing them.

Useful? React with 👍 / 👎.

Address the deferred items from PR #347 review (#326 follow-up).
Eight discrete fixes; the remaining two (vertex-knife near-duplicate
on OnVertex hits, subdivideFacesToQuads T-junctions) are heavier
lifts deferred to a separate PR.

1. HalfEdgeMesh::loopCut rejects mixed quad/tri adjacency upfront.
   Previously walked f1 and f2 independently, so a quad+tri start
   edge produced a one-sided cut on the quad side and silently
   mutated topology. (Codex P1.) +1 unit test.

2. applyWireframeMaterials handles mixed meshes per submesh.
   Tri-only submeshes inside a mesh that had ANY n-gon submesh were
   losing wireframe entirely (boundary overlay only emits n-gon
   submeshes). Now PM_WIREFRAME on tri-only submeshes coexists with
   the boundary overlay on n-gon submeshes. (Codex P2.)

3. buildSubMeshBuffers explicitly clears the GPU vertex/index
   buffers when the submesh has no vertices or no triangles to draw.
   Prior early-return left stale buffers attached, so deleting the
   last face in a submesh kept the old geometry rendering forever.

4. selectedFacesAsHEFaceIndices compacts invalid faces in the
   per-face mapping, not just the per-submesh base offset. Without
   this, a selected face whose raw index is shifted by an earlier
   invalid face mapped to the wrong HE face — silently breaking
   face-mode extrude/delete/dissolve/subdivide.

5. canConvertToQuads predicate replaces !isMeshQuadBased on the
   toolbar gate. Mixed meshes (some submeshes quad, some tri) still
   have tri-only submeshes worth merging — the previous check
   wrongly disabled the action.

6. convertToQuads correctly returns non-zero on promote-only runs.
   Tracks promotion count separately from merge count, returns
   their sum. Previous return-of-totalMerges falsely reported 0
   when only the n-gon promotion happened.

7. deselectFace mirrors selectFace's vertex/edge dilation.
   Without this, ctrl-deselect erased the face triangles but left
   perimeter vertex/edge entries — looked like a stuck partial
   selection.

8. Test in EditModeControllerBevelE2E uses a real (0.001f) translate
   instead of Vector3::ZERO so the commit-path assertion stays
   meaningful even if the controller ever short-circuits zero
   deltas.

Two items remain for a follow-up PR:
- Vertex knife OnVertex clicks producing near-duplicate points
  (the click is converted to first-incident-edge + t=0/1 then
  splitEdge clamps it; need a different splitFace path for true
  vertex hits).
- subdivideFacesToQuads T-junctions on partial n-gon selections
  (needs adjacent-face retriangulation pass like the existing
  tri subdivide does).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 250c412 into master Apr 30, 2026
19 checks passed
@fernandotonon
fernandotonon deleted the fix/quads-bug-sweep branch April 30, 2026 14:55
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