Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setTerrain functionality to TileLayerEdit #3758

Merged
merged 18 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### Unreleased

* Removed Space and Ctrl+Space shortcuts from Layers view to avoid conflict with panning (#3672)
* Scripting: Added API for editing tile layers using terrain sets (with a-morphous, #3758)
* Fixed object preview position with parallax factor on group layer (#3669)
* Fixed hover highlight rendering with active parallax factor (#3669)
* Fixed updating of object selection outlines when changing parallax factor (#3669)
Expand Down
150 changes: 147 additions & 3 deletions docs/scripting-doc/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,8 @@ interface MapEditor {
/**
* Gets the currently selected {@link WangSet} in the "Terrain Sets" view.
*
* See also {@link TileLayerWangEdit}.
*
* @since 1.8
*/
readonly currentWangSet: WangSet
Expand All @@ -2085,6 +2087,8 @@ interface MapEditor {
* The value 0 is used to represent the eraser mode, and the first Wang color
* has index 1.
*
* See also {@link TileLayerWangEdit}.
*
* @since 1.8
*/
readonly currentWangColorIndex: number
Expand Down Expand Up @@ -2845,6 +2849,14 @@ declare class TileLayer extends Layer {
* Returns an object that enables making modifications to the tile layer.
*/
edit() : TileLayerEdit

/**
* Returns an object that enables making modifications to the tile layer
* using the given {@link WangSet}.
*
* @since 1.10.2
*/
wangEdit(wangSet: WangSet) : TileLayerWangEdit
}

/**
Expand All @@ -2861,7 +2873,8 @@ interface TileLayerEdit {
readonly target : TileLayer

/**
* Whether applied edits are mergeable with previous edits. Starts out as false and is automatically set to true by {@link apply}.
* Whether applied edits are mergeable with previous edits. Starts out as
* `false` and is automatically set to `true` by {@link apply}.
*/
mergeable : boolean

Expand All @@ -2880,6 +2893,137 @@ interface TileLayerEdit {
apply() : void
}

/**
* The Wang indexes are arranged as follows:
*
* ```
* 7 0 1
* 6 - 2
* 5 4 3
* ```
*
* These indexes are used by the {@link TileLayerWangEdit}.
*
* @since 1.10.2
*/
declare enum WangIndex {
Top = 0,
TopRight = 1,
Right = 2,
BottomRight = 3,
Bottom = 4,
BottomLeft = 5,
Left = 6,
TopLeft = 7,
NumCorners = 4,
NumEdges = 4,
NumIndexes = 8,
}

/**
* This object enables modifying the tiles on a tile layer using a
* {@link WangSet}. For performance reasons, the changes are not applied
* directly. The {@link apply} function needs to be called when you're done
* making changes.
*
* Note that the results of calling {@link apply} may vary since the changes
* are applied by looking for tiles matching the desired Wang colors, which
* includes a random factor in case of multiple matches.
*
* Colors in a {@link WangSet} are numbered starting from 1. To request no Wang
* color, usually for Wang-aware erasing, use 0. The currently selected {@link
* WangSet} and color are available through {@link MapEditor.currentWangSet}
* and {@link MapEditor.currentWangColorIndex}.
*
* An instance of this object is created by calling {@link TileLayer.wangEdit}.
*
* @since 1.10.2
*/
interface TileLayerWangEdit {
/**
* The target layer of this edit object.
*/
readonly target : TileLayer

/**
* Whether applied edits are mergeable with previous edits. Starts out as
* `false` and is automatically set to `true` by {@link apply}.
*/
mergeable : boolean

/**
* Whether neighboring tiles will be corrected to match up with any marked
* changes once {@link apply} is called. This can cause a larger area to get
* modified. Defaults to `false`.
*/
correctionsEnabled : boolean

/**
* Sets the desired color for the given Wang index at the given location.
*
* This is a low-level function, which only affects the given location and
* does not automatically adjust any neighboring tiles. Use {@link setCorner}
* or {@link setEdge} when that is desired or set {@link correctionsEnabled}
* to `true`.
*/
setWangIndex(x : number, y : number, wangIndex: WangIndex, color : number) : void

/**
* Sets the desired color for the given Wang index at the given location.
*
* This is a low-level function, which only affects the given location and
* does not automatically adjust any neighboring tiles. Use {@link setCorner}
* or {@link setEdge} when that is desired or set {@link correctionsEnabled}
* to `true`.
*/
setWangIndex(pos : point, wangIndex: WangIndex, color : number) : void

/**
* Sets the desired color for the given corner at the given vertex location.
*
* The vertex location refers to a point in between the tiles, where (0, 0) is
* the top-left corner of the map and (mapWidth, mapHeight) is the bottom-right
* corner.
*
* Changing the color of a corner affects all 4 tiles meeting at that corner.
*/
setCorner(x : number, y : number, color : number) : void

/**
* Sets the desired color for the given corner at the given vertex location.
*
* The vertex location refers to a point in between the tiles, where (0, 0) is
* the top-left corner of the map and (mapWidth, mapHeight) is the bottom-right
* corner.
*
* Changing the color of a corner affects all 4 tiles meeting at that corner.
*/
setCorner(pos : point, color : number) : void

/**
* Sets the desired color for the given edge at the given location. Only the
* values {@link WangIndex.Top}, {@link WangIndex.Left}, {@link
* WangIndex.Right} and {@link WangIndex.Bottom} are supported.
*
* Changing the color of an edge affects the 2 tiles connected by that edge.
*/
setEdge(x : number, y : number, edge: WangIndex, color : number) : void

/**
* Sets the desired color for the given edge at the given location. Only the
* values {@link WangIndex.Top}, {@link WangIndex.Left}, {@link
* WangIndex.Right} and {@link WangIndex.Bottom} are supported.
*
* Changing the color of an edge affects the 2 tiles connected by that edge.
*/
setEdge(pos : point, edge: WangIndex, color : number) : void

/**
* Applies all changes made through this object. This object can be reused to make further changes.
*/
apply() : void
}

/**
* Defines a "Terrain Set".
*
Expand Down Expand Up @@ -2921,15 +3065,15 @@ declare class WangSet extends TiledObject {
/**
* Returns the current Wang ID associated with the given tile.
*
* The Wang ID is given by an array of 8 numbers, indicating the colors associated with each index in the following order: [Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, TopLeft].
* The Wang ID is given by an array of 8 numbers, indicating the colors associated with each index in the following order: [Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, TopLeft] (see {@link WangIndex}).
* A value of 0 indicates that no color is associated with a given index.
*/
public wangId(tile : Tile) : number[]

/**
* Sets the Wang ID associated with the given tile.
*
* The Wang ID is given by an array of 8 numbers, indicating the colors associated with each index in the following order: [Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, TopLeft].
* The Wang ID is given by an array of 8 numbers, indicating the colors associated with each index in the following order: [Top, TopRight, Right, BottomRight, Bottom, BottomLeft, Left, TopLeft] (see {@link WangIndex}).
* A value of 0 indicates that no color is associated with a given index.
*
* Make sure the Wang set color count is set before calling this function, because it will raise an error when the Wang ID refers to non-existing colors.
Expand Down
5 changes: 3 additions & 2 deletions src/libtiled/wangset.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* wangset.cpp
* Copyright 2017, Benjamin Trotter <[email protected]>
*
* This file is part of libtiled.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -218,7 +219,7 @@ bool WangId::hasEdgeWithColor(int value) const
/**
* Rotates the wang Id clockwise by (90 * rotations) degrees.
* Meaning with one rotation, the top edge becomes the right edge,
* and the top right corner, becomes the top bottom.
* and the top right corner, becomes the bottom right.
*/
void WangId::rotate(int rotations)
{
Expand Down Expand Up @@ -727,7 +728,7 @@ QList<WangTile> WangSet::sortedWangTiles() const
* 6|X|2
* 5|4|3
*/
WangId WangSet::wangIdFromSurrounding(const WangId surroundingWangIds[]) const
WangId WangSet::wangIdFromSurrounding(const WangId surroundingWangIds[])
{
quint64 id = 0;

Expand Down
3 changes: 2 additions & 1 deletion src/libtiled/wangset.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* wangset.h
* Copyright 2017, Benjamin Trotter <[email protected]>
*
* This file is part of libtiled.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -277,7 +278,7 @@ class TILEDSHARED_EXPORT WangSet : public Object

QList<WangTile> sortedWangTiles() const;

WangId wangIdFromSurrounding(const WangId surroundingWangIds[]) const;
static WangId wangIdFromSurrounding(const WangId surroundingWangIds[]);
WangId wangIdFromSurrounding(const Cell surroundingCells[]) const;

WangId wangIdOfTile(const Tile *tile) const;
Expand Down
4 changes: 2 additions & 2 deletions src/tiled/abstracttilefilltool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ void AbstractTileFillTool::wangFill(TileLayer &tileLayerToFill,
return;

WangFiller wangFiller(*mWangSet, mapDocument()->renderer());

wangFiller.fillRegion(tileLayerToFill, backgroundTileLayer, region);
wangFiller.setRegion(region);
wangFiller.apply(tileLayerToFill, backgroundTileLayer);
}

void AbstractTileFillTool::fillWithStamp(Map &map,
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/debugdrawitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ QRectF DebugDrawItem::boundingRect() const

void DebugDrawItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
for (const Entry &entry : mEntries)
for (const Entry &entry : std::as_const(mEntries))
const_cast<QPicture *>(&entry.picture)->play(painter);
}

Expand Down
62 changes: 61 additions & 1 deletion src/tiled/editabletilelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@

#include "editabletilelayer.h"

#include "addremovetileset.h"
#include "changelayer.h"
#include "editablemanager.h"
#include "editablemap.h"
#include "painttilelayer.h"
#include "resizetilelayer.h"
#include "scriptmanager.h"
#include "tilelayeredit.h"
#include "tilesetdocument.h"
#include "tilelayerwangedit.h"

namespace Tiled {

Expand All @@ -45,6 +48,8 @@ EditableTileLayer::~EditableTileLayer()
{
while (!mActiveEdits.isEmpty())
delete mActiveEdits.first();
while (!mActiveWangEdits.isEmpty())
delete mActiveWangEdits.first();
}

void EditableTileLayer::setSize(QSize size)
Expand Down Expand Up @@ -101,6 +106,61 @@ TileLayerEdit *EditableTileLayer::edit()
return new TileLayerEdit(this);
}

TileLayerWangEdit *EditableTileLayer::wangEdit(EditableWangSet *wangSet)
{
if (!wangSet) {
ScriptManager::instance().throwNullArgError(0);
return nullptr;
}

if (!map()) {
ScriptManager::instance().throwError(QCoreApplication::translate("Script Errors", "Layer not part of a map"));
return nullptr;
}

return new TileLayerWangEdit(this, wangSet);
}

void EditableTileLayer::applyChangesFrom(TileLayer *changes, bool mergeable)
a-morphous marked this conversation as resolved.
Show resolved Hide resolved
{
// Determine painted region and normalize the changes layer
auto paintedRegion = changes->region([] (const Cell &cell) { return cell.checked(); });

// If the painted region is empty there's nothing else to do
if (paintedRegion.isEmpty())
return;

auto rect = paintedRegion.boundingRect();
changes->resize(rect.size(), -rect.topLeft());
const auto tilesets = changes->usedTilesets();

if (mapDocument()) {
// Apply the change using an undo command
auto mapDocument = map()->mapDocument();
auto paint = new PaintTileLayer(mapDocument,
tileLayer(),
rect.x(), rect.y(),
changes,
paintedRegion);
paint->setMergeable(mergeable);

// Add any used tilesets that aren't yet part of the target map
const auto existingTilesets = mapDocument->map()->tilesets();
for (const SharedTileset &tileset : tilesets)
if (!existingTilesets.contains(tileset))
new AddTileset(mapDocument, tileset, paint);

map()->push(paint);
} else {
// Add any used tilesets that aren't yet part of the target map
if (auto map = tileLayer()->map())
map->addTilesets(tilesets);

// Apply the change directly
tileLayer()->setCells(rect.x(), rect.y(), changes, paintedRegion);
}
}

} // namespace Tiled

#include "moc_editabletilelayer.cpp"
9 changes: 8 additions & 1 deletion src/tiled/editabletilelayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
namespace Tiled {

class EditableTile;
class EditableWangSet;
class TileLayerEdit;
class TileLayerWangEdit;

class EditableTileLayer : public EditableLayer
{
Expand Down Expand Up @@ -64,13 +66,18 @@ class EditableTileLayer : public EditableLayer
Q_INVOKABLE Tiled::EditableTile *tileAt(int x, int y) const;

Q_INVOKABLE Tiled::TileLayerEdit *edit();
Q_INVOKABLE Tiled::TileLayerWangEdit *wangEdit(Tiled::EditableWangSet *wangSet);

TileLayer *tileLayer() const;

private:
friend TileLayerEdit;
friend class TileLayerEdit;
friend class TileLayerWangEdit;

QList<TileLayerEdit*> mActiveEdits;
QList<TileLayerWangEdit*> mActiveWangEdits;

void applyChangesFrom(TileLayer *changes, bool mergeable);
};


Expand Down
2 changes: 2 additions & 0 deletions src/tiled/libtilededitor.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ DynamicLibrary {
"tilelayeredit.h",
"tilelayeritem.cpp",
"tilelayeritem.h",
"tilelayerwangedit.cpp",
"tilelayerwangedit.h",
"tilepainter.cpp",
"tilepainter.h",
"tileselectionitem.cpp",
Expand Down
Loading
Loading