Skip to content

Isometric 8-direction sprite export (#724) - #741

Merged
fernandotonon merged 6 commits into
masterfrom
feature/isometric-sprites-724
Jun 20, 2026
Merged

Isometric 8-direction sprite export (#724)#741
fernandotonon merged 6 commits into
masterfrom
feature/isometric-sprites-724

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds ModelIsometricRenderer for headless 8-direction isometric sprite atlases (rows = compass directions, columns = animation frames), reusing the turntable RTT pipeline with stable rest-pose framing and animated sampling via AnimationState::setTimePosition.
  • Wires qtmesh isometric CLI and MCP generate_isometric_sprites (file-in / file-out parity), with Sentry breadcrumbs and JSON report support.
  • Per-cell sizing via --resolution (16–8192); camera framing via --camera-distance (fixed orbit) and --padding (auto-fit multiplier, default 1.25).
  • Review hardening: atlas size caps (4096 cells / 16384 px per side), transform restore after recenter, animation entity matched by clip name, positive --frames validation, file.export breadcrumbs.

Closes #724.

Test plan

  • xvfb-run ./UnitTests --gtest_filter="*Isometric*" — 24 passed locally
  • qtmesh isometric model.fbx -o iso.png — static 8-direction grid
  • qtmesh isometric model.fbx --animation "Walk" --frames 8 -o iso.png — 8×8 animated atlas
  • qtmesh isometric model.fbx -o iso.png --padding 1.5 --camera-distance 5 — framing controls
  • MCP generate_isometric_sprites with same params produces matching output

Summary by CodeRabbit

Release Notes

  • New Features

    • Added headless qtmesh isometric CLI support to export isometric/8-direction sprite atlases (static and animation-sampled), with options for directions, frames, resolution/size, camera distance/padding, and elevation.
    • Added MCP tool generate_isometric_sprites for the same isometric sprite export, with optional JSON output.
  • Documentation

    • Updated CLI docs and website CLI examples/UI with the new isometric command and usage options.
  • Tests

    • Added coverage for the new isometric rendering and CLI/MCP workflows.
  • Chores

    • Bumped project and CI action references to 3.7.0.

Introduces ModelIsometricRenderer, qtmesh isometric CLI, and generate_isometric_sprites MCP tool for production isometric sprite atlases (rows=directions, cols=animation frames). Bump version to 3.7.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new isometric 8-direction animated sprite atlas export capability to QtMeshEditor 3.7.0. A new ModelIsometricRenderer class provides Ogre RTT-based rendering into a directions×frames grid. This is exposed as CLIPipeline::cmdIsometric (CLI) and MCPServer::toolGenerateIsometricSprites (MCP), with build wiring, unit/coverage tests, and updated docs/website/action references.

Changes

Isometric Sprite Atlas Export (v3.7.0)

Layer / File(s) Summary
IsometricOptions struct and ModelIsometricRenderer API with core implementation
src/ModelIsometricRenderer.h, src/ModelIsometricRenderer.cpp
Defines IsometricOptions (width, height, elevation, up-axis, background, direction count, start azimuth, camera distance/padding) and ModelIsometricRenderer with static APIs: renderToGrid (directions×frames Ogre RTT loop with animation stepping and exception handling), composeDirectionGrid (QPainter atlas stitching), directionOrderConvention, shutdown (RTT/camera/light teardown), findEntityWithAnimation, and formatAvailableAnimations. Implementation handles bounds recomputation, entity recentering, camera orbit placement, material shader setup, animation state advancement, and pixel readback.
ModelIsometricRenderer unit tests
src/ModelIsometricRenderer_test.cpp
GTest suite covering empty-entity rejection, null-output-ptr rejection, null-bounds failure, dimension clamping to 16×16 minimum, direction-count grid sizing, composeDirectionGrid sheet dimensions, directionOrderConvention content, shutdown idempotency, and oversized-configuration rejection.
CLIPipeline::cmdIsometric — declaration, dispatcher routing, and integration
src/CLIPipeline.h, src/CLIPipeline.cpp
Declares and routes cmdIsometric: extends printUsage() with isometric options, routes the "isometric" command token in run(), adds ModelIsometricRenderer.h include.
CLIPipeline::cmdIsometric full implementation
src/CLIPipeline.cpp
Parses all flags (--elevation, --directions, --frames, --animation, --size, --resolution, --width, --height, --start-azimuth, --padding, --camera-distance, --json), validates numeric constraints, selects a skinned entity for animation, calls renderToGrid/composeDirectionGrid, writes the PNG, and emits a text summary or JSON with grid/sheet dimensions, elevation/start-azimuth, camera params, direction convention, and animation name.
CLIPipeline::cmdIsometric unit and coverage tests
src/CLIPipeline_test.cpp, src/CLIPipeline_cmdisometric_coverage_test.cpp
Unit tests verify error paths (missing/nonexistent inputs, invalid resolution/camera-distance) and static PNG dimensions; coverage tests exercise full Ogre-backed rendering for static, --json, elevation/azimuth, padding, and conditional animated paths using a real or fallback OBJ mesh. SetUpTestSuite enforces hard assertions for Ogre initialization.
MCPServer::toolGenerateIsometricSprites — declaration, registration, and integration
src/MCPServer.h, src/MCPServer.cpp
Declares and registers toolGenerateIsometricSprites in the tool dispatch map; adds ModelIsometricRenderer.h include.
MCPServer::toolGenerateIsometricSprites implementation and tool schema
src/MCPServer.cpp
Implements the handler with input validation, IsometricOptions construction from MCP arguments (including resolution range validation and optional camera controls with camera_padding/padding alias), transient asset import, animated entity selection, renderToGrid/composeDirectionGrid/save pipeline, and structured JSON response (output path, grid/sheet dimensions, camera distance vs padding, direction convention, animation name); adds the tool schema to buildToolsList().
Build configuration, CLI subcommand registration, and GitHub action metadata
src/CMakeLists.txt, tests/CMakeLists.txt, src/AppLaunchHandler.cpp, action.yml, .github/actions/qtmesh/action.yml
Adds ModelIsometricRenderer.cpp/.h to both source and test build targets; registers "isometric" in isCliSubcommand(); updates action command input descriptions to document the new subcommand.
Version bump to 3.7.0 and comprehensive documentation updates
CMakeLists.txt, README.md, CLAUDE.md, website/src/*, website/src/hooks/useQtmeshActionRef.js, scripts/sync-doc-versions-from-cmake.sh
Bumps project version from 3.6.0 to 3.7.0 across CMakeLists.txt, README.md CI examples, and the website action-ref fallback; adds qtmesh isometric examples to CLAUDE.md, extends CLI subcommand documentation, updates website App.jsx tab, DocsApp.jsx CLI docs section, and content.js pipeline examples; extends sync-doc-versions script to rewrite version-containing markdown patterns.

Sequence Diagram

sequenceDiagram
    participant User as User/CI
    participant CLIPipeline as CLIPipeline::cmdIsometric
    participant MCPServer as MCPServer::toolGenerateIsometricSprites
    participant Renderer as ModelIsometricRenderer
    participant Ogre as Ogre RTT

    rect rgba(100, 149, 237, 0.5)
        Note over User, CLIPipeline: CLI path
        User->>CLIPipeline: qtmesh isometric model.fbx -o out.png --animation Walk --frames 8
        CLIPipeline->>CLIPipeline: parse flags, validate, select skinned entity
    end

    rect rgba(144, 238, 144, 0.5)
        Note over User, MCPServer: MCP path
        User->>MCPServer: generate_isometric_sprites {file, output, animation, frames, directions}
        MCPServer->>MCPServer: validate args, build IsometricOptions, transient import
    end

    CLIPipeline->>Renderer: renderToGrid(entities, animatedEntity, animationName, frameCount, IsometricOptions)
    MCPServer->>Renderer: renderToGrid(entities, animatedEntity, animationName, frameCount, IsometricOptions)

    loop directions × frames
        Renderer->>Ogre: placeCamera(azimuth, elevation)
        Renderer->>Ogre: stepAnimation(frameTime)
        Ogre-->>Renderer: readback → QImage
    end

    Renderer-->>CLIPipeline: outRowsByDirection
    Renderer-->>MCPServer: outRowsByDirection

    CLIPipeline->>Renderer: composeDirectionGrid(rowsByDirection)
    MCPServer->>Renderer: composeDirectionGrid(rowsByDirection)

    Renderer-->>CLIPipeline: QImage atlas
    Renderer-->>MCPServer: QImage atlas

    CLIPipeline->>CLIPipeline: save PNG + optional JSON
    MCPServer->>MCPServer: save PNG + return JSON metadata

    CLIPipeline->>Renderer: shutdown()
    MCPServer->>Renderer: shutdown()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #724 (Epic: Iso — Isometric 8-direction animated sprite sheet export): This PR directly implements all acceptance criteria of the linked epic: static/animated grid rendering, all documented flags, MCP parity, unit/coverage tests, Sentry breadcrumbs, and documentation updates.
  • #727 (Slice A — Core renderer ModelIsometricRenderer): The PR delivers ModelIsometricRenderer.h/.cpp with IsometricOptions, renderToGrid, composeDirectionGrid, directionOrderConvention, and shutdown exactly as specified.
  • #728 (Slice B — CLI subcommand qtmesh isometric): The PR implements CLIPipeline::cmdIsometric with all specified flags and JSON reporting.
  • #725 (Slice C — MCP tool generate_isometric_sprites): The PR implements MCPServer::toolGenerateIsometricSprites with the full parameter set and structured JSON response.
  • #726 (Slice D — CLI/MCP parity, docs, tests): The PR adds CLI coverage tests, unit tests, updates CLAUDE.md, README, website, and action metadata as specified.

Possibly related PRs

  • fernandotonon/QtMeshEditor#184: Both PRs modify the shared GitHub composite action .github/actions/qtmesh/action.yml, with the main PR extending the documented command subcommand list (adding isometric) that the Docker/CI action (#184) introduces.

Poem

🐇 Hop hop, eight ways I look at thee,
North, NE, East — a sprite grid for free!
Each row a direction, each column a frame,
The isometric atlas will never be lame.
From RTT pixels to QPainter's art,
qtmesh isometric — a bunny's new heart! 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% 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 PR title clearly and concisely describes the main feature: isometric 8-direction sprite export with issue reference #724.
Description check ✅ Passed The PR description covers the main changes, implementation approach, test plan, and closes issue #724, aligning well with the provided template structure.
Linked Issues check ✅ Passed The PR comprehensively implements all acceptance criteria from #724: isometric 8-direction grid renderer, CLI/MCP interfaces, animation sampling, framing controls, unit tests, Sentry breadcrumbs, and documentation updates.
Out of Scope Changes check ✅ Passed All code changes directly support the isometric sprite export feature from #724; no unrelated modifications detected in the changeset.

✏️ 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 feature/isometric-sprites-724

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: 05e9397226

ℹ️ 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/ModelIsometricRenderer.cpp Outdated
Comment on lines +457 to +458
const int directions = std::clamp(options.directionCount, 1, 64);
const int frames = std::clamp(frameCount, 1, 360);

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 Reject oversized isometric atlas requests

When a caller uses the accepted maxima, for example --directions 64 --frames 360 at the default 512×512 cell size, these independent clamps let renderToGrid retain 23,040 full-size QImages and then compose a 184,320×32,768 sheet, requiring tens of GiB of memory and likely killing the process instead of returning an error. Please cap the total cells/pixels or stream directly into the final sheet before accepting the request.

Useful? React with 👍 / 👎.

Expose square per-cell resolution on qtmesh isometric and generate_isometric_sprites (range 16–8192), alongside existing --size/--width/--height overrides.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

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

Stale version reference: still shows 3.5.3 instead of 3.7.0.

This inline comment says "(currently 3.5.3)" but CMakeLists.txt now declares VERSION 3.7.0. Update this to "(currently 3.7.0)". Based on learnings, running ./scripts/sync-doc-versions-from-cmake.sh should keep this aligned—verify the script updates this location or add it to the script's substitution list.

📝 Suggested fix
-- **Reproducible builds** — pin the action and the container to the same semver as this repository's `project(QtMeshEditor VERSION …)` in `CMakeLists.txt` (currently **3.5.3**). After bumping the version in CMake, run `./scripts/sync-doc-versions-from-cmake.sh` to refresh the pinned refs in `README.md` and the docs site fallback; CI enforces the match with `./scripts/sync-doc-versions-from-cmake.sh --check`.
+- **Reproducible builds** — pin the action and the container to the same semver as this repository's `project(QtMeshEditor VERSION …)` in `CMakeLists.txt` (currently **3.7.0**). After bumping the version in CMake, run `./scripts/sync-doc-versions-from-cmake.sh` to refresh the pinned refs in `README.md` and the docs site fallback; CI enforces the match with `./scripts/sync-doc-versions-from-cmake.sh --check`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 38, Update the hardcoded version reference in the
README.md's reproducible builds section from "3.5.3" to "3.7.0" to match the
current VERSION declared in CMakeLists.txt. Additionally, verify that the
sync-doc-versions-from-cmake.sh script properly handles this README.md location
when substituting version numbers, and if it does not, add the appropriate
pattern matching for the "(currently **X.Y.Z**)" text to ensure this stays
synchronized automatically in the future.

Source: Learnings

🧹 Nitpick comments (2)
src/ModelIsometricRenderer_test.cpp (1)

13-16: ⚡ Quick win

Align Ogre fixture preconditions with repo test convention.

Add ASSERT_TRUE(canLoadMeshFiles()) in SetUp() so CI fails early with explicit environment diagnostics for Ogre-dependent tests.

Suggested adjustment
     void SetUp() override
     {
         ASSERT_TRUE(tryInitOgre()) << "Ogre init failed (Xvfb/GL required in CI)";
+        ASSERT_TRUE(canLoadMeshFiles()) << "Mesh resources unavailable in test environment";
         ModelIsometricRenderer::shutdown();
     }

Based on learnings: Ogre-dependent QtMeshEditor tests are expected to assert both tryInitOgre() and canLoadMeshFiles() and fail loudly rather than silently skipping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ModelIsometricRenderer_test.cpp` around lines 13 - 16, The SetUp() method
in the test fixture currently only asserts that Ogre initialization succeeds via
tryInitOgre() but does not check if mesh files can be loaded. Add an
ASSERT_TRUE(canLoadMeshFiles()) assertion in the SetUp() method after the
existing tryInitOgre() check to align with the repository's test convention for
Ogre-dependent tests and ensure CI fails early with explicit diagnostics if the
environment cannot load mesh files.

Source: Learnings

src/CLIPipeline_cmdisometric_coverage_test.cpp (1)

187-187: 💤 Low value

Minor inconsistency: ASSERT_EQ vs EXPECT_EQ for return code checks.

This test uses ASSERT_EQ for the cmdIsometric return code (line 187), while the other coverage tests in this file (lines 136, 151, 167) use EXPECT_EQ. Both are valid, but using EXPECT_EQ consistently allows better diagnostics when a command fails (the test continues to report whether the output file exists).

♻️ Proposed fix for consistency
-    ASSERT_EQ(CLIPipeline::cmdIsometric(args.argc(), args.argv()), 0);
+    EXPECT_EQ(CLIPipeline::cmdIsometric(args.argc(), args.argv()), 0);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/CLIPipeline_cmdisometric_coverage_test.cpp` at line 187, Replace the
ASSERT_EQ statement on line 187 with EXPECT_EQ to maintain consistency with the
other coverage tests in this file (lines 136, 151, 167). Change the assertion
that checks CLIPipeline::cmdIsometric(args.argc(), args.argv()) return value
from ASSERT_EQ to EXPECT_EQ so the test continues execution and provides better
diagnostic information if the command fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/CLIPipeline_test.cpp`:
- Around line 1130-1147: The SetUpTestSuite() method in the CLIPipelineCmdTest
fixture currently uses an early return pattern when tryInitOgre() or
canLoadMeshFiles() fail, which causes tests like
CmdIsometric_StaticGridWritesPng to run with unclear failures instead of failing
explicitly. Replace the conditional early return pattern in SetUpTestSuite()
with ASSERT_TRUE() assertions on both tryInitOgre() and canLoadMeshFiles() calls
to ensure that if Ogre initialization or mesh file loading fails, the test suite
fails loudly and immediately rather than continuing with partially initialized
state.

In `@src/CLIPipeline.cpp`:
- Around line 3322-3328: In the argument parsing block for the --frames flag
where parseCliInt is called on argv values into frameCount, add validation after
the successful parse to ensure frameCount is a positive value greater than zero.
If frameCount is not positive, emit an error message using err() with
appropriate context (similar to the existing "Error: Invalid value for --frames"
message) and return exit code 2 to maintain consistency with other argument
validation errors. This validation should occur before setting
frameCountExplicit to true.
- Around line 3448-3459: The current entity selection logic in the loop
iterating through entityList picks the first entity that has a skeleton using
entity->hasSkeleton(), but it should instead verify that the selected entity
actually contains the requested animation clip specified in animationName.
Modify the condition in the skeletal entity detection to check not only if the
entity has a skeleton but also if it contains the specific animation clip
identified by animationName before assigning it to animatedEntity, ensuring that
animatedEntity is set only when both conditions are met.

In `@src/ModelIsometricRenderer.cpp`:
- Around line 183-204: The recenterEntitiesAtOrigin function permanently
translates scene nodes without restoring their original transforms. To fix this,
store the original position or translation offset of each Ogre::SceneNode in the
shifted unordered_set before applying the translation in the for loop, then
after the refreshEntityBounds(entities) call, restore each node's original
transform by translating them back by the positive center offset. This ensures
the entity transformations are temporary and don't persist after the function
completes.
- Around line 510-556: Replace all instances of the non-standard breadcrumb
category "cli.isometric" with a standardized category that follows the
repository's telemetry taxonomy (such as "file.export"). Update all four
SentryReporter::addBreadcrumb() calls in this rendering block to use the same
standardized category instead of "cli.isometric", while keeping the message
content unchanged for the "render start", "render ok", "render failed: Ogre
exception", and "render failed" breadcrumbs.

---

Outside diff comments:
In `@README.md`:
- Line 38: Update the hardcoded version reference in the README.md's
reproducible builds section from "3.5.3" to "3.7.0" to match the current VERSION
declared in CMakeLists.txt. Additionally, verify that the
sync-doc-versions-from-cmake.sh script properly handles this README.md location
when substituting version numbers, and if it does not, add the appropriate
pattern matching for the "(currently **X.Y.Z**)" text to ensure this stays
synchronized automatically in the future.

---

Nitpick comments:
In `@src/CLIPipeline_cmdisometric_coverage_test.cpp`:
- Line 187: Replace the ASSERT_EQ statement on line 187 with EXPECT_EQ to
maintain consistency with the other coverage tests in this file (lines 136, 151,
167). Change the assertion that checks CLIPipeline::cmdIsometric(args.argc(),
args.argv()) return value from ASSERT_EQ to EXPECT_EQ so the test continues
execution and provides better diagnostic information if the command fails.

In `@src/ModelIsometricRenderer_test.cpp`:
- Around line 13-16: The SetUp() method in the test fixture currently only
asserts that Ogre initialization succeeds via tryInitOgre() but does not check
if mesh files can be loaded. Add an ASSERT_TRUE(canLoadMeshFiles()) assertion in
the SetUp() method after the existing tryInitOgre() check to align with the
repository's test convention for Ogre-dependent tests and ensure CI fails early
with explicit diagnostics if the environment cannot load mesh files.
🪄 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: d1192465-de73-4046-988a-419c4a96a521

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce6dfd and a5a83b1.

📒 Files selected for processing (21)
  • .github/actions/qtmesh/action.yml
  • CLAUDE.md
  • CMakeLists.txt
  • README.md
  • action.yml
  • src/AppLaunchHandler.cpp
  • src/CLIPipeline.cpp
  • src/CLIPipeline.h
  • src/CLIPipeline_cmdisometric_coverage_test.cpp
  • src/CLIPipeline_test.cpp
  • src/CMakeLists.txt
  • src/MCPServer.cpp
  • src/MCPServer.h
  • src/ModelIsometricRenderer.cpp
  • src/ModelIsometricRenderer.h
  • src/ModelIsometricRenderer_test.cpp
  • tests/CMakeLists.txt
  • website/src/App.jsx
  • website/src/DocsApp.jsx
  • website/src/data/content.js
  • website/src/hooks/useQtmeshActionRef.js

Comment thread src/CLIPipeline_test.cpp
Comment thread src/CLIPipeline.cpp Outdated
Comment thread src/CLIPipeline.cpp
Comment thread src/ModelIsometricRenderer.cpp Outdated
Comment thread src/ModelIsometricRenderer.cpp Outdated
Expose fixed orbit distance and auto-fit padding via CLI, MCP, and IsometricOptions so sprite framing can be tuned without re-scaling the mesh.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/CLIPipeline_cmdisometric_coverage_test.cpp`:
- Around line 181-190: The CameraPaddingJsonReport test at line 189 currently
only validates file existence with QFile::exists(out), which doesn't catch
corrupt or empty output files. Replace or augment this assertion with a QImage
decode validation to ensure the output is a valid, decodable image file, similar
to what is done in other coverage tests in this file, and optionally validate
the image dimensions as well.
🪄 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: 887a442d-8240-4baf-8b12-bceb94be8057

📥 Commits

Reviewing files that changed from the base of the PR and between a5a83b1 and 29b017b.

📒 Files selected for processing (9)
  • CLAUDE.md
  • src/CLIPipeline.cpp
  • src/CLIPipeline_cmdisometric_coverage_test.cpp
  • src/CLIPipeline_test.cpp
  • src/MCPServer.cpp
  • src/ModelIsometricRenderer.cpp
  • src/ModelIsometricRenderer.h
  • website/src/DocsApp.jsx
  • website/src/data/content.js
✅ Files skipped from review due to trivial changes (2)
  • website/src/data/content.js
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • website/src/DocsApp.jsx
  • src/ModelIsometricRenderer.cpp
  • src/CLIPipeline.cpp
  • src/MCPServer.cpp

Comment thread src/CLIPipeline_cmdisometric_coverage_test.cpp
Cap atlas size before rendering, restore recentered transforms after capture, pick animated entities by clip name, validate positive frame counts, use file.export breadcrumbs, and sync README version text.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/sync-doc-versions-from-cmake.sh`:
- Around line 87-89: The Perl replacement expression with the /e modifier in the
perl -i -pe command at lines 87-89 contains a syntactically invalid replacement
string. The expression (currently **) . $v . (**) fails because the literal
string parts containing parentheses and asterisks are not properly quoted as
Perl strings. Fix this by wrapping the literal string parts in quotes so the
concatenation operator properly joins the quoted string literals with the $v
variable, making the replacement valid Perl code that executes when the /e
modifier is used.
🪄 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: 4b4fbf99-3532-4468-bc00-2eaf676e92cf

📥 Commits

Reviewing files that changed from the base of the PR and between 29b017b and 52e19b7.

📒 Files selected for processing (9)
  • CLAUDE.md
  • README.md
  • scripts/sync-doc-versions-from-cmake.sh
  • src/CLIPipeline.cpp
  • src/CLIPipeline_cmdisometric_coverage_test.cpp
  • src/CLIPipeline_test.cpp
  • src/MCPServer.cpp
  • src/ModelIsometricRenderer.cpp
  • src/ModelIsometricRenderer_test.cpp
✅ Files skipped from review due to trivial changes (1)
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • README.md
  • src/CLIPipeline_test.cpp
  • src/CLIPipeline_cmdisometric_coverage_test.cpp
  • src/ModelIsometricRenderer_test.cpp
  • src/ModelIsometricRenderer.cpp
  • src/MCPServer.cpp
  • src/CLIPipeline.cpp

Comment thread scripts/sync-doc-versions-from-cmake.sh
fernandotonon and others added 2 commits June 19, 2026 18:47
Extract isometric CLI parsing and grid capture helpers, share animation entity lookup, fix RecenterGuard rule compliance, and repair the doc-sync Perl version replacement.

Co-authored-by: Cursor <cursoragent@cursor.com>
Guard render-target update when RTT is unavailable and propagate failure from captureIsometricGrid.

Co-authored-by: Cursor <cursoragent@cursor.com>

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

🧹 Nitpick comments (1)
src/ModelIsometricRenderer.cpp (1)

574-580: Eliminate redundant getAllAnimationStates() call at line 580.

Ogre 14's AnimationStateSet::getAnimationState() is a const method, so it can be called on the const pointer already fetched at line 574. Reuse states directly instead of calling getAllAnimationStates() again:

animState = states->getAnimationState(animationName.toStdString());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ModelIsometricRenderer.cpp` around lines 574 - 580, The code calls
getAllAnimationStates() twice unnecessarily - once at the beginning to assign to
the states variable, and again at line 580 when retrieving the animation state.
Since states is already a const pointer to AnimationStateSet and
getAnimationState() is a const method, eliminate the redundant call by replacing
animatedEntity->getAllAnimationStates()->getAnimationState(animationName.toStdString())
with states->getAnimationState(animationName.toStdString()) to reuse the
previously fetched states pointer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/ModelIsometricRenderer.cpp`:
- Around line 574-580: The code calls getAllAnimationStates() twice
unnecessarily - once at the beginning to assign to the states variable, and
again at line 580 when retrieving the animation state. Since states is already a
const pointer to AnimationStateSet and getAnimationState() is a const method,
eliminate the redundant call by replacing
animatedEntity->getAllAnimationStates()->getAnimationState(animationName.toStdString())
with states->getAnimationState(animationName.toStdString()) to reuse the
previously fetched states pointer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f37a321-e8b7-4451-b41a-c67b8db4200c

📥 Commits

Reviewing files that changed from the base of the PR and between 52e19b7 and fbc3da9.

📒 Files selected for processing (5)
  • scripts/sync-doc-versions-from-cmake.sh
  • src/CLIPipeline.cpp
  • src/MCPServer.cpp
  • src/ModelIsometricRenderer.cpp
  • src/ModelIsometricRenderer.h
🚧 Files skipped from review as they are similar to previous changes (4)
  • scripts/sync-doc-versions-from-cmake.sh
  • src/ModelIsometricRenderer.h
  • src/MCPServer.cpp
  • src/CLIPipeline.cpp

@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit 465af7f into master Jun 20, 2026
21 checks passed
@fernandotonon
fernandotonon deleted the feature/isometric-sprites-724 branch June 20, 2026 00:07
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.

Epic: Iso — Isometric 8-direction animated sprite sheet export

1 participant