Skip to content

Commit

Permalink
Progress on Wang tile functionality (#1638)
Browse files Browse the repository at this point in the history
* Enabled wang filling for BucketFillTool (#1455) and StampBrush
* Added view on all possible wang IDs and allow assigning them to tiles
  • Loading branch information
Bdtrotte authored and bjorn committed Jul 13, 2017
1 parent 9e174f4 commit 09dc14d
Show file tree
Hide file tree
Showing 38 changed files with 2,153 additions and 130 deletions.
8 changes: 7 additions & 1 deletion src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,13 @@ void MapReaderPrivate::readTilesetWangSets(Tileset &tileset)
} else if (xml.name() == QLatin1String("wangtile")) {
const QXmlStreamAttributes tileAtts = xml.attributes();
int tileId = tileAtts.value(QLatin1String("tileid")).toInt();
unsigned wangId = tileAtts.value(QLatin1String("wangid")).toUInt();
unsigned wangId = tileAtts.value(QLatin1String("wangid")).toUInt(nullptr, 16);

if (!wangSet->wangIdIsValid(wangId)) {
xml.raiseError(QLatin1String("Invalid wangId given for tileId: ") + QString::number(tileId));
return;
}

bool fH = tileAtts.value(QLatin1String("hflip")).toInt();
bool fV = tileAtts.value(QLatin1String("vflip")).toInt();
bool fA = tileAtts.value(QLatin1String("dflip")).toInt();
Expand Down
3 changes: 2 additions & 1 deletion src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,8 @@ void MapWriterPrivate::writeTileset(QXmlStreamWriter &w, const Tileset &tileset,
for (const WangTile &wangTile : ws->wangTiles()) {
w.writeStartElement(QLatin1String("wangtile"));
w.writeAttribute(QLatin1String("tileid"), QString::number(wangTile.tile()->id()));
w.writeAttribute(QLatin1String("wangid"), QString::number(wangTile.wangId()));
w.writeAttribute(QLatin1String("wangid"),
QLatin1String("0x") + QString::number(wangTile.wangId(), 16));

if (wangTile.flippedHorizontally())
w.writeAttribute(QLatin1String("hflip"), QString::number(1));
Expand Down
239 changes: 221 additions & 18 deletions src/libtiled/wangset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "wangset.h"

#include <QStack>
#include <QtMath>

using namespace Tiled;

Expand All @@ -48,6 +49,91 @@ unsigned wangTileToTileInfo(const WangTile &wangTile)
| (wangTile.flippedAntiDiagonally() << 27);
}

int WangId::edgeColor(int index) const
{
int shift = (index * 8);

int color = (mId >> shift) & 0xf;

return color;
}

int WangId::cornerColor(int index) const
{
int shift = (index * 8) + 4;

int color = (mId >> shift) & 0xf;

return color;
}

void WangId::setEdgeColor(int index, unsigned value)
{
value = value & 0xf;
mId &= ~(0xf << (index * 8));
mId |= value << (index * 8);
}

void WangId::setCornerColor(int index, unsigned value)
{
value = value & 0xf;
mId &= ~(0xf << (index * 8 + 4));
mId |= value << (index * 8 + 4);
}

bool WangId::hasEdgeWildCards() const
{
for (int i = 0; i < 4; ++i) {
if (!edgeColor(i))
return true;
}

return false;
}

bool WangId::hasCornerWildCards() const
{
for (int i = 0; i < 4; ++i) {
if (!cornerColor(i))
return true;
}

return false;
}

void WangId::rotate(int rotations)
{
if (rotations < 0)
rotations = 4 + (rotations % 4);
else
rotations %= 4;

unsigned rotated = mId << rotations*8;
rotated = rotated | (mId >> ((4 - rotations) * 8));

mId = rotated;
}

void WangId::flipHorizontally()
{
WangId newWangId = mId;

newWangId.setEdgeColor(1, edgeColor(3));
newWangId.setEdgeColor(3, edgeColor(1));

for (int i = 0; i < 4; ++i) {
newWangId.setCornerColor(i, cornerColor(3-i));
}

mId = newWangId;
}

void WangId::flipVertically()
{
flipHorizontally();
rotate(2);
}

void WangTile::translate(int map[])
{
int mask = (mFlippedHorizontally << 2)
Expand All @@ -64,27 +150,31 @@ void WangTile::translate(int map[])
void WangTile::rotateRight()
{
int map[] = {5, 4, 1, 0, 7, 6, 3, 2};
mWangId.rotate(1);

translate(map);
}

void WangTile::rotateLeft()
{
int map[] = {3, 2, 7, 6, 1, 0, 5, 4};
mWangId.rotate(3);

translate(map);
}

void WangTile::flipHorizontally()
{
int map[] = {4, 3, 6, 1, 0, 7, 2, 5};
mWangId.flipHorizontally();

translate(map);
}

void WangTile::flipVertically()
{
int map[] = {2, 5, 0, 7, 6, 1, 4, 3};
mWangId.flipVertically();

translate(map);
}
Expand Down Expand Up @@ -116,33 +206,96 @@ WangSet::WangSet(Tileset *tileset,
{
}

void WangSet::addTile(Tile *tile, WangId wangId)
QList<Tile *> WangSet::tilesChangedOnSetEdgeColors(int newEdgeColors)
{
QList<Tile *> tiles;

int previousEdgeColors = mEdgeColors;
mEdgeColors = newEdgeColors;

for (auto i = mTileInfoToWangId.cbegin(); i != mTileInfoToWangId.cend(); ++i) {
if (!wangIdIsValid(i.value())) {
int tileId = i.key() & 0x1fffffff;
tiles.append(mTileset->tileAt(tileId));
}
}

mEdgeColors = previousEdgeColors;

return tiles;
}

QList<Tile *> WangSet::tilesChangedOnSetCornerColors(int newCornerColors)
{
Q_ASSERT(tile->tileset() == mTileset);
Q_ASSERT(wangIdIsValid(wangId));
QList<Tile *> tiles;

int previousCornerColors = mCornerColors;
mCornerColors = newCornerColors;

mWangIdToWangTile.insert(wangId, WangTile(tile, wangId));
mTileInfoToWangId.insert(tile->id(), wangId);
for (auto i = mTileInfoToWangId.cbegin(); i != mTileInfoToWangId.cend(); ++i) {
if (!wangIdIsValid(i.value())) {
int tileId = i.key() & 0x1fffffff;
tiles.append(mTileset->tileAt(tileId));
}
}

mCornerColors = previousCornerColors;

return tiles;
}

void WangSet::addCell(const Cell &cell, WangId wangId)
void WangSet::addTile(Tile *tile, WangId wangId)
{
Q_ASSERT(cell.tileset() == mTileset);
Q_ASSERT(wangIdIsValid(wangId));
addWangTile(WangTile(tile, wangId));
}

mWangIdToWangTile.insert(wangId, WangTile(cell, wangId));
mTileInfoToWangId.insert(cellToTileInfo(cell), wangId);
void WangSet::addCell(const Cell &cell, WangId wangId)
{
addWangTile(WangTile(cell, wangId));
}

void WangSet::addWangTile(const WangTile &wangTile)
{
Q_ASSERT(wangTile.tile()->tileset() == mTileset);
Q_ASSERT(wangIdIsValid(wangTile.wangId()));

if (WangId previousWangId = mTileInfoToWangId.value(wangTileToTileInfo(wangTile))) {
if (wangTile.wangId() == 0) {
removeWangTile(wangTile);
return;
}
if (previousWangId == wangTile.wangId())
return;
removeWangTile(wangTile);
}

if (wangTile.wangId() == 0)
return;

mWangIdToWangTile.insert(wangTile.wangId(), wangTile);
mTileInfoToWangId.insert(wangTileToTileInfo(wangTile), wangTile.wangId());
}

void WangSet::removeTile(Tile *tile)
{
removeWangTile(WangTile(tile, 0));
}

void WangSet::removeCell(const Cell &cell)
{
removeWangTile(WangTile(cell, 0));
}

void WangSet::removeWangTile(const WangTile &wangTile)
{
WangId wangId = mTileInfoToWangId.take(wangTileToTileInfo(wangTile));

WangTile w = wangTile;
w.setWangId(wangId);

mWangIdToWangTile.remove(wangId, w);
}

WangTile WangSet::findMatchingWangTile(WangId wangId) const
{
auto potentials = findMatchingWangTiles(wangId);
Expand All @@ -165,7 +318,7 @@ QList<WangTile> WangSet::findMatchingWangTiles(WangId wangId) const
//Stores the space of a wild card, followed by how many colors that space can have.
QVector<WangWildCard> wildCards;

if (mEdgeColors > 0) {
if (mEdgeColors > 1) {
for (int i = 0; i < 4; ++i) {
if (!wangId.edgeColor(i)) {
WangWildCard w;
Expand All @@ -177,7 +330,7 @@ QList<WangTile> WangSet::findMatchingWangTiles(WangId wangId) const
}
}

if (mCornerColors > 0) {
if (mCornerColors > 1) {
for (int i = 0; i < 4; ++i) {
if (!wangId.cornerColor(i)) {
WangWildCard w;
Expand Down Expand Up @@ -209,12 +362,12 @@ QList<WangTile> WangSet::findMatchingWangTiles(WangId wangId) const

WangWildCard top = stack.pop();
top.colorCount -= 1;
if (top.colorCount > 0)
if (top.colorCount >= 0)
stack.push(top);
} else {
WangWildCard top = stack.pop();
top.colorCount -= 1;
if (top.colorCount > 0) {
if (top.colorCount >= 0) {
stack.push(top);

for (int i = stack.size(); i < max; ++i)
Expand All @@ -238,12 +391,12 @@ WangId WangSet::wangIdFromSurrounding(WangId surroundingWangIds[]) const
{
unsigned id = 0;

if (mEdgeColors > 0) {
if (mEdgeColors > 1) {
for (int i = 0; i < 4; ++i)
id |= (surroundingWangIds[i*2].edgeColor((2 + i) % 4)) << (i*8);
}

if (mCornerColors > 0) {
if (mCornerColors > 1) {
for (int i = 0; i < 4; ++i) {
int color = surroundingWangIds[i*2 + 1].cornerColor((2 + i) % 4);

Expand All @@ -267,9 +420,20 @@ WangId WangSet::wangIdFromSurrounding(const Cell surroundingCells[]) const
for (int i = 0; i < 8; ++i)
wangIds[i] = wangIdOfCell(surroundingCells[i]);

WangId wangId = wangIdFromSurrounding(wangIds);
return wangIdFromSurrounding(wangIds);
}

return wangId;
QList<Tile *> WangSet::tilesWithWangId() const
{
if (!mTileset)
return QList<Tile *>();

QList<Tile *> tiles;

for (WangTile wangTile : mWangIdToWangTile)
tiles.append(wangTile.tile());

return tiles;
}

WangId WangSet::wangIdOfTile(const Tile *tile) const
Expand All @@ -288,11 +452,50 @@ bool WangSet::wangIdIsValid(WangId wangId) const
if (wangId.edgeColor(i) > mEdgeColors
|| wangId.cornerColor(i) > mCornerColors)
return false;

if (mEdgeColors <= 1)
if (wangId.edgeColor(i))
return false;

if (mCornerColors <= 1)
if (wangId.cornerColor(i))
return false;
}

return true;
}

bool WangSet::wangIdIsUsed(WangId wangId) const
{
return mWangIdToWangTile.contains(wangId);
}

WangId WangSet::templateWangIdAt(unsigned n) const
{
unsigned wangId = 0;
//number of permutations of a corner and edge together.
int cornerEdgePermutations = mEdgeColors * mCornerColors;

for (int i = 7; i >= 0; --i) {
//this is the number of permutations possible bellow this point in the wangId
int belowPermutations = qPow(cornerEdgePermutations, i/2) * ((i&1)? mEdgeColors : 1);
int value = n / belowPermutations;
n -= value * belowPermutations;

wangId |= value << i * 4;
}

//before this is like a base 10 range (0 - 9) where we want (1 - 10) for each digit
wangId += 0x11111111;
//If edges/corners don't have variations then those spots should be wild.
if (mEdgeColors <= 1)
wangId &= 0xf0f0f0f0;
if (mCornerColors <= 1)
wangId &= 0x0f0f0f0f;

return wangId;
}

WangSet *WangSet::clone(Tileset *tileset) const
{
WangSet *c = new WangSet(tileset, mEdgeColors, mCornerColors, mName, mImageTileId);
Expand Down
Loading

0 comments on commit 09dc14d

Please sign in to comment.