Skip to content

TiledQuick: Add border and grid over mapitem.#4392

Merged
bjorn merged 17 commits into
mapeditor:masterfrom
UltraDagon:master
May 22, 2026
Merged

TiledQuick: Add border and grid over mapitem.#4392
bjorn merged 17 commits into
mapeditor:masterfrom
UltraDagon:master

Conversation

@UltraDagon
Copy link
Copy Markdown
Contributor

@UltraDagon UltraDagon commented Mar 5, 2026

Draws a simple 1px-width border around MapItem using the Qt Scene Graph. The border is drawn on top of the map, and the color is changeable within tiledquick/qml/main.qml.

Draws a grid across the map. The color is changeable within tiledquick/qml/main.qml. The grid's dash length, space length after dash, and thickness are changeable within libtiledquick/grid.frag.

This is my first pull request, so I chose a small feature and wanted to practice mirroring the existing style and standards. This problem has also helped me gain some experience with QtQuick, and I plan on implementing the mouse-following grid-snapping object found in the default Tiled next.

As part of my attempt to imitate the existing style, I have kept my in-code comments to a minimum. Please let me know if including more comments is the better practice, and I can go back and add them.

Any and all feedback is appreciated!

@kody-ai
Copy link
Copy Markdown

kody-ai Bot commented Mar 9, 2026

Code review by Kody

We are evaluating the use of AI for automated code reviews. Your feedback is welcome! Please share your thoughts at #4399.

Comment thread src/libtiledquick/mapborderitem.cpp
@UltraDagon UltraDagon changed the title TiledQuick: Add border surrounding mapitem TiledQuick: Add border and grid over mapitem. Mar 20, 2026
@UltraDagon
Copy link
Copy Markdown
Contributor Author

UltraDagon commented Mar 20, 2026

Update: Added Grid over mapitem

Created the following files to make the new GPU-rendered grid feature:

  • mapgriditem.h/cpp: The QT item that houses and updates the mapgridmaterial, which draws the grid using a shader.
  • mapgridmaterial.h/cpp: Builds and passes values into the grid shader.
  • grid.vert: The vertex shader that defines the bounding box for the fragment shader.
  • grid.frag: The fragment shader that defines what pixels should change at which positions. Contains the math for how the grid is defined.

Other files were updated for the following reasons:

  • Add the grid QT item into main.qml.
  • Register and support the grid QT item and newly created files.
  • Support the use of the qtshadertools module.

This addition was much larger than my last one, and I am definitely expecting to have gotten some of it wrong. Any and all feedback is appreciated!

I added a few comments pointing out areas I'd like feedback on, if possible. Thank you!

Comment thread src/libtiledquick/libtiledquick.qbs
Comment thread src/libtiledquick/libtiledquick.qbs
Comment thread src/libtiledquick/libtiledquick.qbs Outdated
Comment thread src/libtiledquick/libtiledquick.qbs Outdated
Comment thread src/tiledquick/qml/main.qml Outdated
id: mapGriditem
anchors.fill: mapItem

gridSize: mapItem.pixelToTileCoords(width, height);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For this property, I am not sure if this is the best way to get this information. Please let me know if there is a better way to get the grid size (X tiles by Y tiles) or tile size (in pixels).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess there isn't yet. I think we'll need to somehow expose the loaded map as a EditableMap instance, which would make the necessary properties accessible from QML.

Comment thread appveyor.yml
Copy link
Copy Markdown
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

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

This is quite a nice change, @UltraDagon, thanks for looking into these things!

I wondered a little about the purpose of the MapBorderItem as opposed to a standard Rectangle item, but I see the latter does not have a "cosmetic" mode so its border width would need to be inverse-adjusted to the scale to render at 1px. The specialized MapBorderItem might be the better solution.

I've tweaked the MapGridItem's fragment shader a little to place the grid on the edge between the tiles rather than on the tile. It really only makes difference in case of a width > 1 but it seems like this way we also didn't need the specific checks to disable the leftmost and topmost lines.

Comment thread src/libtiledquick/libtiledquick.qbs
Comment thread src/libtiledquick/libtiledquick.qbs
Comment thread src/libtiledquick/libtiledquick.qbs Outdated
Comment thread src/tiledquick/qml/main.qml Outdated
id: mapGriditem
anchors.fill: mapItem

gridSize: mapItem.pixelToTileCoords(width, height);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess there isn't yet. I think we'll need to somehow expose the loaded map as a EditableMap instance, which would make the necessary properties accessible from QML.

Comment thread appveyor.yml
@UltraDagon
Copy link
Copy Markdown
Contributor Author

Thank you for the feedback, Bjorn! I will work to get these changes finished within a few days.

@UltraDagon UltraDagon requested a review from bjorn April 17, 2026 21:17
@UltraDagon
Copy link
Copy Markdown
Contributor Author

I ended up using mapItem's mMap to get the tile size information, and from that, I was able to get the grid size in tiles.

Copy link
Copy Markdown
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

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

I've pushed some further tweaks and left you some more feedback. It's not quite ready for merging yet, but getting close. :-)

Comment thread src/libtiledquick/mapgriditem.cpp Outdated
material->mPixelWidth = width();
material->mPixelHeight = height();
material->mTileWidth = width() / mGridSize.x();
material->mTileHeight = height() / mGridSize.y();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This may divide by zero when mGridSize isn't set. But I think more interesting is that MapGridItem actually needs the tile size, not the grid size. So I'd suggest to rename mGridSize to mTileSize and set it accordingly, so that here we can just assign that to the material.

Comment thread src/libtiledquick/mapgridmaterial.cpp Outdated
auto *m = static_cast<const MapGridMaterial *>(other);
return (mColor == m->mColor &&
qFuzzyCompare(mScale, m->mScale) &&
qFuzzyCompare(mPixelWidth, m->mPixelWidth) ? 0 : 1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this is doing what the compare function should be doing. The Qt docs talk about returning -1, 0 or 1, to establish a rendering order for materials that reduces state switches. Then again I'm also not entirely sure at the moment which properties are relevant in that case.

Why did you choose these properties and left out mPixelHeight, mTileWidth and mTileHeight?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I had forgotten to add the rest of the comparable properties. Good catch, thank you!

Comment thread src/tiledquick/qml/main.qml Outdated
id: mapGriditem
anchors.fill: mapItem

gridSize: Qt.point(width / mapItem.tileSize().width, height / mapItem.tileSize().height);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Alright, so I just noticed the MapGridMaterial really just needs the tile size, so it's extra odd to do this calculation here. This should just be:

Suggested change
gridSize: Qt.point(width / mapItem.tileSize().width, height / mapItem.tileSize().height);
tileSize: mapItem.tileSize();

Once you've made the other suggested change. :-)

Comment thread src/tiledquick/qml/main.qml Outdated
var mapRelativeCoords = singleFingerPanArea.mapToItem(mapItem, singleFingerPanArea.mouseX, singleFingerPanArea.mouseY)
var tileCoords = mapItem.screenToTileCoords(mapRelativeCoords.x, mapRelativeCoords.y)
Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y)
Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y);
Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y)

Just suggesting to revert addition of semicolon. I'm open to changing to coding style, but then we'll do it consistently. :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry about that! I use that text area for testing and left it there by mistake.

@bjorn
Copy link
Copy Markdown
Member

bjorn commented May 16, 2026

@UltraDagon Hmm, you've opened this PR from your master branch and are now conflating too many unrelated changes. I think adding grid and border in the same PR was still fine, but let's close that first and then open a new PR for the EditableMap related change. I can try to help if you're unfamiliar with managing branches in git, let me know on Discord.

@UltraDagon
Copy link
Copy Markdown
Contributor Author

Successfully split the maploader/editablemap changes into it's own pull request (#4520)!

@UltraDagon
Copy link
Copy Markdown
Contributor Author

Would you like me to add the copyright headers to all files added in the pull request?

@bjorn
Copy link
Copy Markdown
Member

bjorn commented May 21, 2026

Would you like me to add the copyright headers to all files added in the pull request?

I've added them to the source files mostly for consistency. I think now only the shaders do not have them, but you could add a brief comment to them as well. I personally wouldn't put the full copyright header there (it's actually a rather old habit by now I guess, which I haven't extended to QML files either). I think we could also merge this change as-is now.

@UltraDagon
Copy link
Copy Markdown
Contributor Author

My apologies, I misread the commit and thought that only mapgridmaterial.h/cpp had the copyright headers. I agree that it would make more sense to only have the headers in the source files and leave them out of the other files. It should be good to merge, and I'll update my other PR to change the QML to use the new editablemap property.

@bjorn bjorn merged commit 34dfd73 into mapeditor:master May 22, 2026
15 checks passed
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.

2 participants