Skip to content

Commit

Permalink
Provide feedback when the Terrain Brush can't find some tiles (#3778)
Browse files Browse the repository at this point in the history
When the Terrain Brush and Wang Fill Mode can't find some tiles, these
locations are now marked in red and the text "Missing terrain
transition" appears on the status bar.

This change does not affect the Stamp Brush in Wang Fill Mode for now,
and the "Missing terrain transition" text only appears for the Terrain 
Brush.
  • Loading branch information
bjorn committed Aug 4, 2023
1 parent fb2390a commit 396eeff
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 61 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### Unreleased

* Added support for setting custom properties on the project (#2903)
* Added feedback when Terrain Brush and Terrain Fill Mode can't find a tile
* Removed Space and Ctrl+Space shortcuts from Layers view to avoid conflict with panning (#3672)
* Display the image base name for unnamed tile objects referring to single images
* Scripting: Added API for editing tile layers using terrain sets (with a-morphous, #3758)
Expand Down
12 changes: 10 additions & 2 deletions src/tiled/abstracttilefilltool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "brushitem.h"
#include "mapdocument.h"
#include "stampactions.h"
#include "wangbrush.h"
#include "wangfiller.h"

#include <QAction>
Expand All @@ -32,9 +33,10 @@ AbstractTileFillTool::AbstractTileFillTool(Id id,
const QString &name,
const QIcon &icon,
const QKeySequence &shortcut,
BrushItem *brushItem,
QObject *parent)
: AbstractTileTool(id, name, icon, shortcut, brushItem, parent)
: AbstractTileTool(id, name, icon, shortcut,
new WangBrushItem,
parent)
, mFillMethod(TileFill)
, mStampActions(new StampActions(this))
, mWangSet(nullptr)
Expand Down Expand Up @@ -194,6 +196,8 @@ void AbstractTileFillTool::updatePreview(const QRegion &fillRegion)
mFillBounds = fillRegion.boundingRect();
auto preview = SharedMap::create(mapDocument()->map()->parameters());

static_cast<WangBrushItem*>(brushItem())->setInvalidTiles(QRegion());

switch (mFillMethod) {
case TileFill:
fillWithStamp(*preview, mStamp, fillRegion);
Expand Down Expand Up @@ -230,6 +234,8 @@ void AbstractTileFillTool::updatePreview(const QRegion &fillRegion)
void AbstractTileFillTool::clearOverlay()
{
brushItem()->clear();
static_cast<WangBrushItem*>(brushItem())->setInvalidTiles(QRegion());

mPreviewMap.clear();
}

Expand Down Expand Up @@ -289,6 +295,8 @@ void AbstractTileFillTool::wangFill(TileLayer &tileLayerToFill,
WangFiller wangFiller(*mWangSet, backgroundTileLayer, mapDocument()->renderer());
wangFiller.setRegion(region);
wangFiller.apply(tileLayerToFill);

static_cast<WangBrushItem*>(brushItem())->setInvalidTiles(wangFiller.invalidRegion());
}

void AbstractTileFillTool::fillWithStamp(Map &map,
Expand Down
1 change: 0 additions & 1 deletion src/tiled/abstracttilefilltool.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ class AbstractTileFillTool : public AbstractTileTool
const QString &name,
const QIcon &icon,
const QKeySequence &shortcut,
BrushItem *brushItem = nullptr,
QObject *parent = nullptr);
~AbstractTileFillTool() override;

Expand Down
1 change: 0 additions & 1 deletion src/tiled/bucketfilltool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ BucketFillTool::BucketFillTool(QObject *parent)
QIcon(QLatin1String(
":images/22/stock-tool-bucket-fill.png")),
QKeySequence(Qt::Key_F),
nullptr,
parent)
, mLastFillMethod(mFillMethod)
{
Expand Down
1 change: 0 additions & 1 deletion src/tiled/shapefilltool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ ShapeFillTool::ShapeFillTool(QObject *parent)
QIcon(QLatin1String(
":images/22/rectangle-fill.png")),
QKeySequence(Qt::Key_P),
nullptr,
parent)
, mToolBehavior(Free)
, mCurrentShape(Rect)
Expand Down
71 changes: 18 additions & 53 deletions src/tiled/wangbrush.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "wangbrush.h"

#include "addremovetileset.h"
#include "brushitem.h"
#include "containerhelpers.h"
#include "geometry.h"
#include "hexagonalrenderer.h"
Expand All @@ -38,53 +37,30 @@

namespace Tiled {

class WangBrushItem : public BrushItem
{
public:
WangBrushItem()
: BrushItem()
, mIsValid(true) {}

QRectF boundingRect() const override;

void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget) override;

void setInvalidTiles(const QRegion &region = QRegion());
bool isValid() const { return mIsValid; }

private:
//there is a current brush
bool mIsValid;
//The tiles which can't be painted.
QRegion mInvalidTiles;
};

QRectF WangBrushItem::boundingRect() const
{
if (mIsValid) {
return BrushItem::boundingRect();
} else {
QRect bounds = mInvalidTiles.boundingRect();
QRectF bounding = mapDocument()->renderer()->boundingRect(bounds);
auto bounds = BrushItem::boundingRect();

// Adjust for border drawn at tile selection edges
bounding.adjust(-1, -1, 1, 1);
if (!isValid()) {
QRect invalidTileBounds = mInvalidTiles.boundingRect();
QRectF invalidPixelBounds = mapDocument()->renderer()->boundingRect(invalidTileBounds);

return bounding;
// Adjust for border drawn at tile selection edges
bounds |= invalidPixelBounds.adjusted(-1, -1, 1, 1);
}

return bounds;
}

void WangBrushItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
if (mIsValid) {
BrushItem::paint(painter, option, widget);
} else {
BrushItem::paint(painter, option, widget);

if (!isValid()) {
const MapRenderer *renderer = mapDocument()->renderer();
QColor invalid(255, 0, 0, 64);
const QColor invalid(255, 0, 0, 128);

renderer->drawTileSelection(painter,
mInvalidTiles,
Expand All @@ -95,16 +71,14 @@ void WangBrushItem::paint(QPainter *painter,

void WangBrushItem::setInvalidTiles(const QRegion &region)
{
if (region.isEmpty()) {
mIsValid = true;
} else {
mIsValid = false;
mInvalidTiles = region;
if (mInvalidTiles == region)
return;

update();
}
mInvalidTiles = region;
update();
}


WangBrush::WangBrush(QObject *parent)
: AbstractTileTool("WangTool",
tr("Terrain Brush"),
Expand Down Expand Up @@ -498,15 +472,6 @@ static constexpr QPoint aroundTilePoints[WangId::NumIndexes] = {
QPoint(-1, -1)
};

// 3 0
// 2 1
static constexpr QPoint aroundVertexPoints[WangId::NumCorners] = {
QPoint( 0, -1),
QPoint( 0, 0),
QPoint(-1, 0),
QPoint(-1, -1)
};

void WangBrush::updateBrush()
{
brushItem()->clear();
Expand Down Expand Up @@ -591,7 +556,7 @@ void WangBrush::updateBrush()
wangFiller.setCorrectionsEnabled(true);
wangFiller.apply(*stamp);

static_cast<WangBrushItem*>(brushItem())->setInvalidTiles();
static_cast<WangBrushItem*>(brushItem())->setInvalidTiles(wangFiller.invalidRegion());

// Translate to map coordinate space and normalize stamp
QRegion brushRegion = stamp->region([] (const Cell &cell) { return cell.checked(); });
Expand Down
20 changes: 20 additions & 0 deletions src/tiled/wangbrush.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,31 @@
#pragma once

#include "abstracttiletool.h"
#include "brushitem.h"
#include "wangfiller.h"
#include "wangset.h"

namespace Tiled {

class WangBrushItem : public BrushItem
{
public:
WangBrushItem() {}

QRectF boundingRect() const override;

void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget) override;

void setInvalidTiles(const QRegion &region);
bool isValid() const { return mInvalidTiles.isEmpty(); }

private:
// The tiles which can't be painted.
QRegion mInvalidTiles;
};

class WangBrush : public AbstractTileTool
{
Q_OBJECT
Expand Down
7 changes: 6 additions & 1 deletion src/tiled/wangfiller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,13 @@ static void updateAdjacent(WangFiller::CellInfo &adjacentInfo, WangId wangId, in
}
}

/**
* Applies the scheduled Wang changes to the \a target layer.
*/
void WangFiller::apply(TileLayer &target)
{
mInvalidRegion = QRegion();

auto &grid = mFillRegion.grid;
auto &region = mFillRegion.region;

Expand Down Expand Up @@ -249,7 +254,7 @@ void WangFiller::apply(TileLayer &target)

Cell cell;
if (!findBestMatch(target, grid, QPoint(x, y), cell)) {
// TODO: error feedback
mInvalidRegion += QRect(x, y, 1, 1);
return;
}

Expand Down
8 changes: 6 additions & 2 deletions src/tiled/wangfiller.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@ class WangFiller
void setCorner(QPoint vertexPos, int color);
void setEdge(QPoint pos, WangId::Index index, int color);

void apply(TileLayer &target);

/**
* Applies the scheduled Wang changes to the \a target layer.
* Returns the region with locations for which a matching tile could not be
* found in the last call to apply().
*/
void apply(TileLayer &target);
const QRegion &invalidRegion() const { return mInvalidRegion; }

private:
/**
Expand All @@ -109,6 +112,7 @@ class WangFiller
bool mCorrectionsEnabled = false;
bool mErasingEnabled = true;
FillRegion mFillRegion;
QRegion mInvalidRegion;

QPainter *mDebugPainter = nullptr;
};
Expand Down

0 comments on commit 396eeff

Please sign in to comment.