Skip to content

quads chunk 4: wire enterEditMode to n-gon import - #332

Merged
fernandotonon merged 4 commits into
feat/quadsfrom
feat/quads-4-edit-mode-ngon
Apr 28, 2026
Merged

quads chunk 4: wire enterEditMode to n-gon import#332
fernandotonon merged 4 commits into
feat/quadsfrom
feat/quads-4-edit-mode-ngon

Conversation

@fernandotonon

Copy link
Copy Markdown
Owner

Summary

Chunk 4 of the quad migration (#326). First chunk where the n-gon path is reachable through the normal Edit Mode flow — and the first chunk worth smoke testing manually.

When a user imports a mesh, Tabs into Edit Mode, and the source asset has quads, the editor now sees those quads as EditableFace n-gons (not Assimp's diagonal triangulation) — preparing the ground for Catmull-Clark subdivide (chunk 5) and loop cut (chunk 7).

Modification tracking

The whole chunk hinges on a single-bit invariant: if qtme.source_path is set on the Ogre mesh, the mesh matches the source; if not, the mesh has been edited (or was never imported).

  • EditableMesh::commitToEntity (same-count edits) and resizeEntityBuffers (topology edits) wipe the path on every commit.
  • EditModeController::enterEditMode checks the path: present → loadFromAssimpFile (n-gon); absent → loadFromEntity (legacy).

This means user edits never get clobbered by re-imports, and procedural / .scene.glb / post-edit entries fall back cleanly.

Tests (+5; Ogre-bound — Linux CI only)

  • commitToEntity wipes qtme.source_path.
  • resizeEntityBuffers wipes qtme.source_path.
  • enterEditMode uses the n-gon path when source_path is set (faces non-empty for a quad OBJ).
  • enterEditMode falls back to legacy when source_path absent (faces empty).
  • After commit-and-exit, re-entering uses the legacy path.

The 197 standalone tests still pass.

Test plan

  • App builds clean.
  • 197 standalone tests green.
  • Linux/macOS/Windows CI.
  • Manual smoke: import an asset with quads (e.g. a Blender-exported OBJ/FBX/glTF), Tab into Edit Mode. With chunks 5+ unimplemented, you won't see Catmull-Clark / loop cut yet, but EditModeController::currentMesh()->subMeshes()[s].faces should be non-empty in the inspector for source-quad submeshes.

Towards #326.

🤖 Generated with Claude Code

fernandotonon and others added 2 commits April 28, 2026 08:55
* fix(scan): harden scan --fix and improve reporting

Fix scan --fix crashes in Ogre/Assimp paths, prevent FBX simplify from bloating files, and enrich scan output with [fixed]/[skipped] tags plus saved-bytes and keys-removed summaries. Default viewport FSAA to 0 when unset and add a regression test.

Made-with: Cursor

* fix(tests): accept compacted FBX animation curves

FBX animation curve channels may be emitted with a single key when the channel is constant. Relax the AnimationCurves test accordingly.

Also replace a `strlen`-based suffix length with `std::string_view` sizing for Sonar.

Made-with: Cursor
Hooks Edit Mode into the loadFromAssimpFile path added in chunk 3, so
fresh-imported assets enter Edit Mode with their source quads intact
in EditableSubMesh::faces.

Modification tracking:
  - commitToEntity (same-count edits) and resizeEntityBuffers (topology
    edits) wipe the qtme.source_path cached on Ogre::Mesh. After any
    user edit, the live GPU buffers diverge from the source file, so
    re-importing would discard the edit.
  - This makes "is this mesh modified?" a single-bit invariant: if
    qtme.source_path is set, the mesh matches the source; if not, the
    mesh has diverged (or was never imported, e.g. procedural primitives).

enterEditMode flow:
  1. If qtme.source_path is set → loadFromAssimpFile (n-gon path).
  2. Else (or on re-import failure) → loadFromEntity (legacy path).

Procedural primitives, .scene.glb sub-entities, post-edit re-entries,
and any path that doesn't carry a source path all fall back cleanly.

Tests (+5; Ogre-bound, run on Linux CI):
  - commitToEntity wipes the cached path.
  - resizeEntityBuffers wipes the cached path.
  - enterEditMode uses the n-gon path when source_path is set
    (faces non-empty for a quad OBJ).
  - enterEditMode falls back to legacy when source_path absent
    (faces empty — chunk-1 invariant preserved).
  - After commit-and-exit, re-entering uses the legacy path.

Towards #326. Smoke-testable end-to-end: import a quad asset, Tab into
Edit Mode, the inspector should report n-gon submeshes with face count
matching the source file. Catmull-Clark and loop cut land in chunks 5
and 7 on top of this.

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

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c2d2d3a5-e6c7-4d22-9a21-33a03d270699

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/quads-4-edit-mode-ngon

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

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: 93e2b33c2f

ℹ️ 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 +302 to +304
if (!sourcePath.empty()
&& m_editableMesh->loadFromAssimpFile(sourcePath)) {
loaded = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve import-space transforms before n-gon reimport

This call now routes imported meshes through loadFromAssimpFile whenever qtme.source_path exists, but that loader reads raw Assimp geometry without the transform pipeline used by normal import (notably aiProcess_ConvertToLeftHanded and the Z-up bake done in MeshProcessor). For formats like FBX (and especially Z-up assets), entering Edit Mode can therefore load vertices in a different basis than the live Ogre mesh; on exit with commit, commitToEntity writes those mismatched positions back and can mirror/rotate geometry even when the user made no intentional shape change.

Useful? React with 👍 / 👎.

Comment thread src/EditModeController.cpp Outdated
Comment on lines +303 to +304
&& m_editableMesh->loadFromAssimpFile(sourcePath)) {
loaded = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep bone-handle mapping when enabling n-gon path

Using loadFromAssimpFile here also changes bone-index semantics for skinned meshes: that path stores assignments with mesh-local indices, while the normal importer writes Ogre bone handles. After any topology edit that triggers resizeEntityBuffers, those local indices are re-emitted as if they were handles, so skinning can bind vertices to the wrong bones when aiBone order does not match Ogre handle order. The new unconditional n-gon routing makes this reachable for any imported rigged asset with qtme.source_path.

Useful? React with 👍 / 👎.

fernandotonon and others added 2 commits April 28, 2026 13:11
The original AssimpToOgreImporter applies aiProcess_ConvertToLeftHanded
to every non-.x asset, which flips X (and inverts UV V) so Ogre's
left-handed coordinate system gets correct geometry. My chunk-4
loadFromAssimpFile re-imported the same source file without that flag,
so EditableMesh ended up in the original (right-handed) coordinate
space while the rendered Ogre buffers were in the flipped (left-handed)
space. The vertex / edge / face overlays in Edit Mode therefore drew
mirrored relative to the on-screen mesh. (Reported manually on a Tom &
Jerry asset — overlay points appeared reflected through the Y-Z plane.)

Fix:
  - MeshImporterExporter::importer caches the convert-to-left-handed
    decision alongside the source path on Ogre::Mesh
    (qtme.source_convert_lh).
  - EditableMesh::loadFromAssimpFile gains a `convertToLeftHanded`
    parameter (default true to match the importer's typical behaviour).
    Applies aiProcess_ConvertToLeftHanded when set.
  - EditModeController::enterEditMode reads the cached flag and passes
    it through, so the editable mesh ends up in the same coordinate
    system as the rendered Ogre buffers.
  - commitToEntity / resizeEntityBuffers now wipe both
    qtme.source_path AND qtme.source_convert_lh on user edits — the
    pair is conceptually one cache entry.

Existing 6 LoadFromAssimpFile tests still green (default param keeps
their behaviour identical).

Towards #326.

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

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit fec543a into feat/quads Apr 28, 2026
35 checks passed
@fernandotonon
fernandotonon deleted the feat/quads-4-edit-mode-ngon branch April 28, 2026 23:34
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