Skip to content

feat(export): vertex colors + .mesh sidecar materials - #346

Merged
fernandotonon merged 11 commits into
masterfrom
feat/export-vertex-colors-material-reimport
Apr 30, 2026
Merged

feat(export): vertex colors + .mesh sidecar materials#346
fernandotonon merged 11 commits into
masterfrom
feat/export-vertex-colors-material-reimport

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Export vertex colors to Assimp-based formats (glTF/GLB/OBJ/DAE/PLY/...) from Ogre VES_DIFFUSE.
  • Export vertex colors to FBX by writing LayerElementColor (ByPolygonVertex/Direct).
  • Fix .mesh reimport material fallback by auto-loading <basename>.material sidecar when present (prevents BaseWhite).

Test plan

  • UnitTests (CI) — added coverage tests:
    • MeshImporterExporterTest.Importer_MeshLoadsSidecarMaterialScript
    • FBXExporterCoverageTest.VertexColors_WritesLayerElementColor

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Per-vertex colors are preserved and exported to FBX (including from bind/pose data) and included in mesh exports.
    • Mesh import now detects and loads accompanying material sidecar files.
    • New API to flush pending vertex-paint into the active mesh/entity before export.
  • Tests

    • Added tests for vertex-color FBX export and round-trip import with sidecar material files.

Assimp-based exports now emit vertex colors from VES_DIFFUSE and FBX exports write LayerElementColor. Also load exported .material sidecars when reimporting .mesh so material names don't fall back to BaseWhite.

Made-with: Cursor
@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds per-vertex color export to FBX by emitting a LayerElementColor (ByPolygonVertex/Direct) expanded to polygon-vertex order; persists vertex colors through Assimp meshes and exports bind-pose colors; adds sidecar .material loading during .mesh import; exposes EditModeController::flushPendingVertexPaintForEntity and adds tests for FBX color export and sidecar materials.

Changes

Cohort / File(s) Summary
FBX Exporter
src/FBX/FBXExporter.cpp, src/FBX/FBXExporter_test.cpp
Detects VES_DIFFUSE per-vertex colors, converts to RGBA doubles, expands colors to per-polygon-vertex using exporter winding (reversed), writes LayerElementColor node (Version, Name, MappingInformationType=ByPolygonVertex, ReferenceInformationType=Direct, Colors[]) and registers it in the geometry Layer. Test validates presence, mapping/reference, color count/order, and LayerElement registration.
Mesh Import/Export & Sidecar Material
src/MeshImporterExporter.cpp, src/MeshImporterExporter_test.cpp
Exports/imports per-vertex diffuse into aiMesh::mColors[0] with appropriate ABGR/ARGB conversion; flushes editor vertex-paint before export and exports bind-pose colors; .mesh import now checks for and loads a sibling <name>.material script, initializes resource group, parses/loads declared materials, and the test verifies round-trip material resolution.
Edit Mode / Vertex Paint Flush API
src/EditModeController.h, src/EditModeController.cpp
Adds public void EditModeController::flushPendingVertexPaintForEntity(Ogre::Entity*) (declaration + implementation) to commit deferred vertex-paint for the active edit entity; used to ensure paints are flushed before export.

Sequence Diagram(s)

sequenceDiagram
    participant Mesh as Mesh (positions, indices, VES_DIFFUSE)
    participant Exporter as FBXExporter
    participant Geometry as FBX Geometry Node
    participant Layer as FBX Layer Registry

    Mesh->>Exporter: provide vertex data + VES_DIFFUSE
    Exporter->>Exporter: detect VES_DIFFUSE, convert to RGBA doubles
    Exporter->>Exporter: expand to ByPolygonVertex order (reversed winding)
    Exporter->>Geometry: create LayerElementColor (Version, Name, Mapping=ByPolygonVertex, Reference=Direct, Colors[])
    Exporter->>Layer: register LayerElement(Type="LayerElementColor", TypedIndex=0)
    Layer->>Geometry: attach color layer to geometry
Loading
sequenceDiagram
    participant Importer as MeshImporterExporter
    participant FS as File System
    participant Parser as Material Parser
    participant Resources as Ogre Resource Manager
    participant Mesh as Ogre Mesh Loader

    Importer->>FS: check for "<mesh>.material" sidecar
    FS-->>Importer: file found / not found
    alt sidecar exists
        Importer->>FS: read .material script
        FS-->>Importer: script contents
        Importer->>Parser: parse material script
        Parser-->>Importer: parsed material names
        Importer->>Resources: init/load resource group & register parsed materials
        Resources->>Mesh: materials available for mesh import
        Mesh->>Importer: imported mesh with sidecar materials resolved
    else no sidecar
        Importer->>Importer: proceed without sidecar
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through vertices, color in paw,
Painted each corner, obeying the draw,
Sidecar scripts sang their material tune,
FBX kept my hues beneath sun and moon,
A tiny rabbit cheers — export done! 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely and clearly summarizes the two main changes: vertex color export and .mesh sidecar material loading.
Description check ✅ Passed The description covers the key features and includes test plan details, but lacks Technical Details section from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/export-vertex-colors-material-reimport

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 60 minutes.

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: 387f337e6a

ℹ️ 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 thread src/MeshImporterExporter.cpp Outdated
{
// `.mesh` stores material names, but not the script definitions. If the
// corresponding `.material` isn't loaded, Ogre falls back to BaseWhite.
const QString sidecar = meshFile.path() + "/" + meshFile.baseName() + ".material";

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 Resolve sidecar name from complete basename

QFileInfo::baseName() truncates at the first dot, so a mesh like robot.v2.mesh looks for robot.material instead of robot.v2.material. In that common versioned-file naming case, the sidecar script is never loaded and import still falls back to BaseWhite, which defeats the new .mesh sidecar fix.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/FBX/FBXExporter_test.cpp (1)

1274-1303: Assert the exported color payload, not just the node presence.

This test would still pass if LayerElementColor is emitted with an empty or misexpanded Colors array. Verifying the payload shape here would better protect the new export path.

Suggested tightening of the test
-    EXPECT_NE(geomNodes[0]->find("LayerElementColor"), nullptr);
+    auto* colorElement = geomNodes[0]->find("LayerElementColor");
+    ASSERT_NE(colorElement, nullptr);
+    auto* colors = colorElement->find("Colors");
+    ASSERT_NE(colors, nullptr);
+    EXPECT_EQ(colors->properties[0].doubleArray.size(), 12u);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FBX/FBXExporter_test.cpp` around lines 1274 - 1303, The test
VertexColors_WritesLayerElementColor currently only checks for the presence of a
LayerElementColor node; update it to assert the actual exported color payload by
locating the matching LayerElement (via layer->findAll("LayerElement") and
Type=="LayerElementColor") and then verifying it contains a "Colors" child with
the expected array length and values (compare against the colors from
createInMemoryTriangleMeshWithVertexColors) and that each Colors entry has the
correct property types/values; do this using the existing
exportAndParse/find/findAll helpers on geomNodes[0] so the test fails if Colors
is empty or misserialized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/MeshImporterExporter_test.cpp`:
- Around line 332-380: The test Importer_MeshLoadsSidecarMaterialScript can pass
incorrectly because SidecarMaterial already exists in-process; before calling
MeshImporterExporter::importer({outMesh}) remove or clear the runtime material
so only the sidecar script can provide it. Locate the test's setup where
Ogre::MaterialPtr mat is created (SidecarMaterial) and before reimport call into
MeshImporterExporter::importer, call the MaterialManager to destroy/remove the
runtime material (e.g. use Ogre::MaterialManager::getSingleton().remove or
equivalent to remove "SidecarMaterial") or reset the manager's material state so
the reimport must load the sidecar file to satisfy the material lookup. Ensure
the code removes the exact name "SidecarMaterial" and that no lingering
references remain before import.

In `@src/MeshImporterExporter.cpp`:
- Around line 314-334: exportCurrentPose() currently creates its own aiMesh but
never copies Ogre::VES_DIFFUSE, so vertex colors are dropped; modify
exportCurrentPose() (or factor out the color-copy logic into a helper used by
both paths) to detect colElem =
vData->vertexDeclaration->findElementBySemantic(Ogre::VES_DIFFUSE) for the
pose's vertex buffer, allocate aiMesh->mColors[0] with new
aiColor4D[aiMesh->mNumVertices], read the buffer via vbuf->lock(...), convert
using colElem->getType() (VET_COLOUR_ABGR vs default) into Ogre::ColourValue
then assign aiColor4D(cv.r,cv.g,cv.b,cv.a) for each vertex and vbuf->unlock();
ensure proper ownership/cleanup consistent with the shared export path.

---

Nitpick comments:
In `@src/FBX/FBXExporter_test.cpp`:
- Around line 1274-1303: The test VertexColors_WritesLayerElementColor currently
only checks for the presence of a LayerElementColor node; update it to assert
the actual exported color payload by locating the matching LayerElement (via
layer->findAll("LayerElement") and Type=="LayerElementColor") and then verifying
it contains a "Colors" child with the expected array length and values (compare
against the colors from createInMemoryTriangleMeshWithVertexColors) and that
each Colors entry has the correct property types/values; do this using the
existing exportAndParse/find/findAll helpers on geomNodes[0] so the test fails
if Colors is empty or misserialized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83b15001-2289-4b5b-9b9d-ce94e99dd821

📥 Commits

Reviewing files that changed from the base of the PR and between ae1370a and 387f337.

📒 Files selected for processing (4)
  • src/FBX/FBXExporter.cpp
  • src/FBX/FBXExporter_test.cpp
  • src/MeshImporterExporter.cpp
  • src/MeshImporterExporter_test.cpp

Comment thread src/MeshImporterExporter_test.cpp
Comment thread src/MeshImporterExporter.cpp
Deferred GPU upload from vertex painting could leave Ogre buffers stale when export ran in the same frame. Sync EditableMesh colors to the entity before reading geometry for Assimp and FBX paths (including scene glTF export).

Made-with: Cursor
…x colors

- Sidecar material test: destroy export entity, release material handle, remove
  from MaterialManager when still loaded so reimport must parse .material.
- FBX vertex color test: assert ByPolygonVertex Colors array length and RGBA
  order after reversed winding (v0 red, v2 blue, v1 green).
- exportCurrentPose: copy VES_DIFFUSE from bind-pose buffers like UVs.
- Shorten flushPendingVertexPaintForEntity doc comment.

Made-with: Cursor
ensureResourceGroup initialises the mesh folder before tryLoadSidecarMaterialScript;
a second initialiseResourceGroup is a no-op, so materials from the in-memory
parse never reached a loaded state and mesh import fell back to BaseWhite.

Made-with: Cursor
- Use mutable QByteArray and read-only MemoryDataStream instead of
  (void*)constData() (const-correctness / Sonar).
- Extract loadUnloadedOgreMaterialsInGroup to keep tryLoadSidecarMaterialScript
  simpler.
- Keep explicit load of UNLOADED materials in the mesh folder group so .mesh
  reimport resolves sidecar materials after parseScript.

Made-with: Cursor

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/FBX/FBXExporter_test.cpp (1)

1275-1278: ⚡ Quick win

Use unique mesh/node names to avoid test resource collisions.

Lines 1275 and 1277 use hardcoded resource names. Reusing uniqueName(...) (as the rest of this fixture does) reduces flakiness when tests are repeated in the same process.

Suggested patch
-    auto meshPtr = createInMemoryTriangleMeshWithVertexColors("fbx_colors");
+    const auto name = uniqueName("fbx_colors");
+    auto meshPtr = createInMemoryTriangleMeshWithVertexColors(name);
     ASSERT_TRUE(!!meshPtr);
-    auto* node = Manager::getSingleton()->addSceneNode("fbx_colors_node");
+    auto* node = Manager::getSingleton()->addSceneNode(name + "_node");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FBX/FBXExporter_test.cpp` around lines 1275 - 1278, Replace the hardcoded
resource names with generated unique names to prevent collisions: call
uniqueName(...) when creating the mesh via
createInMemoryTriangleMeshWithVertexColors (instead of "fbx_colors") and when
adding the scene node via Manager::getSingleton()->addSceneNode (instead of
"fbx_colors_node"), and pass the matched unique name into
Manager::getSingleton()->createEntity so the mesh/node pair use the same unique
identifier.
src/EditModeController.cpp (1)

1483-1489: ⚡ Quick win

Add a file.export breadcrumb for this export-time flush path.

This method performs a significant export-prep operation (forcing pending vertex colors into Ogre buffers) but currently emits no breadcrumb.

Suggested patch
 void EditModeController::flushPendingVertexPaintForEntity(Ogre::Entity* entity)
 {
     if (!entity || !m_editModeActive || m_editEntity != entity || !m_editableMesh)
         return;
+    SentryReporter::addBreadcrumb(
+        "file.export",
+        QStringLiteral("Flushed pending vertex paint before export for entity '%1'")
+            .arg(QString::fromStdString(entity->getName())));
     m_vertexPaintFlushPending = false;
     m_editableMesh->commitVertexColorsToEntity(m_editEntity);
 }

As per coding guidelines: “All user-facing actions and significant operations must be tracked with SentryReporter::addBreadcrumb(category, message). Use ... 'file.import'/'file.export' for I/O operations.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/EditModeController.cpp` around lines 1483 - 1489, Add a Sentry breadcrumb
when forcing pending vertex colors to the Ogre buffers in
EditModeController::flushPendingVertexPaintForEntity: after confirming the
early-return checks and before/after clearing m_vertexPaintFlushPending and
calling m_editableMesh->commitVertexColorsToEntity(m_editEntity), invoke
SentryReporter::addBreadcrumb("file.export", "flushPendingVertexPaintForEntity:
committed vertex colors for entity"); this ensures the export-time flush is
tracked as a file.export I/O breadcrumb.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/FBX/FBXExporter_test.cpp`:
- Around line 1284-1286: The test dereferences the result of
findTopLevel(r.nodes, "Objects") (stored in objects) without a null check;
update the test to assert objects is not null before using it (e.g., replace
direct dereference with an ASSERT_NE(objects, nullptr) or ASSERT_TRUE(objects)
immediately after calling findTopLevel), then proceed to call
objects->findAll("Geometry") and ASSERT_EQ(geomNodes.size(), 1u) only after that
guard; reference findTopLevel, objects, findAll, and ASSERT_EQ to locate the
lines to update.

---

Nitpick comments:
In `@src/EditModeController.cpp`:
- Around line 1483-1489: Add a Sentry breadcrumb when forcing pending vertex
colors to the Ogre buffers in
EditModeController::flushPendingVertexPaintForEntity: after confirming the
early-return checks and before/after clearing m_vertexPaintFlushPending and
calling m_editableMesh->commitVertexColorsToEntity(m_editEntity), invoke
SentryReporter::addBreadcrumb("file.export", "flushPendingVertexPaintForEntity:
committed vertex colors for entity"); this ensures the export-time flush is
tracked as a file.export I/O breadcrumb.

In `@src/FBX/FBXExporter_test.cpp`:
- Around line 1275-1278: Replace the hardcoded resource names with generated
unique names to prevent collisions: call uniqueName(...) when creating the mesh
via createInMemoryTriangleMeshWithVertexColors (instead of "fbx_colors") and
when adding the scene node via Manager::getSingleton()->addSceneNode (instead of
"fbx_colors_node"), and pass the matched unique name into
Manager::getSingleton()->createEntity so the mesh/node pair use the same unique
identifier.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acdaf90f-ec9d-42bf-a5b8-8fe36a3f3d0b

📥 Commits

Reviewing files that changed from the base of the PR and between 387f337 and af37daf.

📒 Files selected for processing (5)
  • src/EditModeController.cpp
  • src/EditModeController.h
  • src/FBX/FBXExporter_test.cpp
  • src/MeshImporterExporter.cpp
  • src/MeshImporterExporter_test.cpp

Comment thread src/FBX/FBXExporter_test.cpp
Comment thread src/MeshImporterExporter.cpp
…aterials

- Resolve sidecar as completeBaseName.material so model.v2.mesh finds model.v2.material.
- After parseScript, load only materials declared on Ogre material script lines (prefix material + name);
  remove loadResourceGroup and full-group material iteration so unrelated broken scripts cannot fail import.
- FBX vertex-color test: unique mesh/node names, ASSERT_NE(objects).
- EditModeController: file.export Sentry breadcrumb in flushPendingVertexPaintForEntity;
  expand flush API doc comment (CodeRabbit docstring / observability).

Made-with: Cursor
- Run loadResourceGroup immediately after parseScript (matches CI-passing flow).
- Keep declared-name loads, then sweep only UNLOADED materials in the mesh folder group.
- Removes try/catch that could mask load failures; declared-name trim/load unchanged.

Made-with: Cursor
@fernandotonon
fernandotonon force-pushed the feat/export-vertex-colors-material-reimport branch from b079449 to add7506 Compare April 30, 2026 02:26

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
src/MeshImporterExporter.cpp (1)

1063-1080: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep sidecar loading scoped to the parsed script.

loadResourceGroup(group) plus the final LOADSTATE_UNLOADED sweep still makes this import depend on every material resource in the mesh directory, not just the sidecar you just parsed. That reintroduces the same failure mode this PR is trying to remove: one unrelated broken sibling .material or missing texture can throw here and make a valid .mesh fall back again. Please keep the post-parse load limited to the material names extracted from scriptBytes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MeshImporterExporter.cpp` around lines 1063 - 1080, The current code
calls rgm.loadResourceGroup(group) and then iterates all Ogre::MaterialManager
resources to load any LOADSTATE_UNLOADED entries, which forces loading every
material in the folder and reintroduces failures from unrelated siblings;
instead, remove the broad rgm.loadResourceGroup(group) + UNLOADED sweep and
restrict loading to only the materials parsed from the scriptBytes. Modify
loadMaterialsDeclaredInOgreMaterialScript to return (or expose) the list of
material names it found, then iterate that list and for each name call
Ogre::MaterialManager::getSingleton().getByName(materialName, group) (or
getResourceByName) and call res->load() only if res exists and
res->getLoadingState() == Ogre::Resource::LOADSTATE_UNLOADED; keep
rgm.initialiseResourceGroup(group) only if needed for sidecar lookup but do not
perform a global group load or a full MaterialManager iterator sweep.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/MeshImporterExporter.cpp`:
- Around line 1063-1080: The current code calls rgm.loadResourceGroup(group) and
then iterates all Ogre::MaterialManager resources to load any LOADSTATE_UNLOADED
entries, which forces loading every material in the folder and reintroduces
failures from unrelated siblings; instead, remove the broad
rgm.loadResourceGroup(group) + UNLOADED sweep and restrict loading to only the
materials parsed from the scriptBytes. Modify
loadMaterialsDeclaredInOgreMaterialScript to return (or expose) the list of
material names it found, then iterate that list and for each name call
Ogre::MaterialManager::getSingleton().getByName(materialName, group) (or
getResourceByName) and call res->load() only if res exists and
res->getLoadingState() == Ogre::Resource::LOADSTATE_UNLOADED; keep
rgm.initialiseResourceGroup(group) only if needed for sidecar lookup but do not
perform a global group load or a full MaterialManager iterator sweep.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5837ea09-b0b9-4d60-861d-fd1f1450e3ac

📥 Commits

Reviewing files that changed from the base of the PR and between af37daf and add7506.

📒 Files selected for processing (4)
  • src/EditModeController.cpp
  • src/EditModeController.h
  • src/FBX/FBXExporter_test.cpp
  • src/MeshImporterExporter.cpp
✅ Files skipped from review due to trivial changes (1)
  • src/EditModeController.cpp

- loadMaterialsDeclaredInOgreMaterialScript returns whether any declared
  material exists in the mesh folder group after disk init
- Run memory parseScript only when none were found (avoids duplicate-
  material exceptions that skipped loadResourceGroup and left BaseWhite)
- Keep unload sweep after each load path

Made-with: Cursor
MeshSerializer writes SubMesh::getMaterialName(); SubEntity::setMaterial
does not update the mesh asset. Without this the exported .mesh did not
reference SidecarMaterial and reimport always resolved to BaseWhite.

Made-with: Cursor

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
src/MeshImporterExporter.cpp (1)

1057-1094: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope the sidecar load to this script’s materials only.

loadResourceGroup(group) and sweepUnloadedInGroup() still load every material in the folder resource group, so one unrelated broken .material or missing texture can still derail this mesh import and send it back to BaseWhite. Please keep the load set limited to the names declared in scriptBytes instead of doing a group-wide load/sweep.

Possible direction
-        if (rgm.isResourceGroupInitialised(group))
-            rgm.loadResourceGroup(group);
-        else
+        if (!rgm.isResourceGroupInitialised(group))
             rgm.initialiseResourceGroup(group);

-        auto sweepUnloadedInGroup = [&group]() {
-            ...
-        };
-
-        bool haveDeclared = loadMaterialsDeclaredInOgreMaterialScript(scriptBytes, group);
-        sweepUnloadedInGroup();
+        const auto declaredNames = /* parse names from scriptBytes once */;
+        bool haveDeclared = /* check/load only declaredNames */;

         if (!haveDeclared)
         {
             ...
             Ogre::MaterialManager::getSingleton().parseScript(ds, group);
-            if (rgm.isResourceGroupInitialised(group))
-                rgm.loadResourceGroup(group);
-            loadMaterialsDeclaredInOgreMaterialScript(scriptBytes, group);
-            sweepUnloadedInGroup();
+            /* load only declaredNames here too */
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MeshImporterExporter.cpp` around lines 1057 - 1094, The group-wide loads
are too broad—replace calls to rgm.loadResourceGroup(group) and
sweepUnloadedInGroup() with logic that only parses and loads the materials named
in the currently parsed scriptBytes; use
loadMaterialsDeclaredInOgreMaterialScript(scriptBytes, group) to obtain the
set/list of declared material names, then for each name call
Ogre::MaterialManager::getSingleton().getByName(name, group) or
getResource(name) and explicitly load() that ResourcePtr (and only sweep/load
those entries) instead of loading the entire resource group or iterating all
materials; keep the parseScript(ds, group) step but remove the subsequent
rgm.loadResourceGroup(group)/sweepUnloadedInGroup() calls so failures are scoped
to the script’s declared materials.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/MeshImporterExporter.cpp`:
- Around line 1057-1094: The group-wide loads are too broad—replace calls to
rgm.loadResourceGroup(group) and sweepUnloadedInGroup() with logic that only
parses and loads the materials named in the currently parsed scriptBytes; use
loadMaterialsDeclaredInOgreMaterialScript(scriptBytes, group) to obtain the
set/list of declared material names, then for each name call
Ogre::MaterialManager::getSingleton().getByName(name, group) or
getResource(name) and explicitly load() that ResourcePtr (and only sweep/load
those entries) instead of loading the entire resource group or iterating all
materials; keep the parseScript(ds, group) step but remove the subsequent
rgm.loadResourceGroup(group)/sweepUnloadedInGroup() calls so failures are scoped
to the script’s declared materials.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fc68dfa8-6051-4545-9f81-aa0cf0e32928

📥 Commits

Reviewing files that changed from the base of the PR and between add7506 and baca1d5.

📒 Files selected for processing (2)
  • src/MeshImporterExporter.cpp
  • src/MeshImporterExporter_test.cpp

@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 3e8d507 into master Apr 30, 2026
19 checks passed
@fernandotonon
fernandotonon deleted the feat/export-vertex-colors-material-reimport branch April 30, 2026 06:05
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