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

Wang Tiles #1582

Merged
merged 26 commits into from
Jul 4, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
904e8bc
Created WangSet class, as well as some functions for wangIds
Bdtrotte May 28, 2017
cb8d9ae
Moved wangId into a class of its own
Bdtrotte May 29, 2017
e93cc74
Merge branch 'master' into WangTiles
Bdtrotte Jun 11, 2017
c329a97
Merge branch 'master' of https://github.com/bjorn/tiled into WangTiles
Bdtrotte Jun 21, 2017
4757fb6
Refined WangSet class, and added them into Tileset
Bdtrotte Jun 21, 2017
31689c6
Made requested changes
Bdtrotte Jun 21, 2017
e10151e
Enabled file saving and loading. (Needs testing)
Bdtrotte Jun 24, 2017
c7e67d0
Fixed some issues with saving/loading
willt Jun 23, 2017
0ef5add
Style update
Bdtrotte Jun 25, 2017
74dbae3
Foundation for adding UI support to wangTile assignment
Bdtrotte Jun 27, 2017
400d47c
merged upstream
Bdtrotte Jun 27, 2017
ff6c624
Added a couple Undo commands, and made a bit more progress on the mod…
Bdtrotte Jun 28, 2017
3916cd6
WangSets are now able to be created and edited from the ui
Bdtrotte Jun 28, 2017
acae98a
Added new files to tiled.pro
Bdtrotte Jun 28, 2017
68bd9af
adjusted reading/writting so that all the wang set info (including ti…
Bdtrotte Jun 28, 2017
52ae862
Cleaned up a few things
Bdtrotte Jun 29, 2017
4398cea
remoced references to 'addremocewangset
Bdtrotte Jun 29, 2017
7f58709
Now can assign wangsets an image, added functions for getting the wan…
Bdtrotte Jun 30, 2017
bb6b98a
Beging to store info about tile rotation and inversion
Bdtrotte Jul 2, 2017
0969d46
Wangsets now store info about rotation and flipping, mapreader/writer…
Bdtrotte Jul 2, 2017
8b959a9
Merge branch 'wip/wangtiles' into WangTiles
Bdtrotte Jul 4, 2017
1df48f5
Made requested changes
Bdtrotte Jul 4, 2017
25f8494
Merge branch 'WangTiles' of https://github.com/Bdtrotte/tiled into Wa…
Bdtrotte Jul 4, 2017
888ea7b
fixed issue in 'wangIdFromSurrounding'
Bdtrotte Jul 4, 2017
825774a
Made requested changes!
Bdtrotte Jul 4, 2017
0d3f353
Removed file that should not be in version control
bjorn Jul 4, 2017
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
6 changes: 4 additions & 2 deletions src/libtiled/libtiled-src.pri
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ SOURCES += $$PWD/compression.cpp \
$$PWD/tileset.cpp \
$$PWD/tilesetformat.cpp \
$$PWD/tilesetmanager.cpp \
$$PWD/varianttomapconverter.cpp
$$PWD/varianttomapconverter.cpp \
$$PWD/wangset.cpp
HEADERS += $$PWD/compression.h \
$$PWD/filesystemwatcher.h \
$$PWD/gidmapper.h \
Expand Down Expand Up @@ -65,4 +66,5 @@ HEADERS += $$PWD/compression.h \
$$PWD/tileset.h \
$$PWD/tilesetformat.h \
$$PWD/tilesetmanager.h \
$$PWD/varianttomapconverter.h
$$PWD/varianttomapconverter.h \
$$PWD/wangset.h
2 changes: 2 additions & 0 deletions src/libtiled/libtiled.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ DynamicLibrary {
"tilesetmanager.h",
"varianttomapconverter.cpp",
"varianttomapconverter.h",
"wangset.cpp",
"wangset.h",
]

Group {
Expand Down
148 changes: 148 additions & 0 deletions src/libtiled/wangset.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* wangset.cpp
* Copyright 2017, Benjamin Trotter <bdtrotte@ucsc.edu>
* This file is part of libtiled.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "wangset.h"

#include <QStack>
#include <QPoint>

using namespace Tiled;

WangSet::WangSet(Tileset *tileset,
int edgeColors,
int cornerColors,
QString name,
int imageTileId):
Object(Object::TerrainType), //for now, will add unique type soon
mTileSet(tileset),
mEdgeColors(edgeColors),
mCornerColors(cornerColors),
mName(std::move(name)),
mImageTileId(imageTileId),
mWangIdToTile(QMultiMap<WangId, Tile*>()),
mTileIdToWangId(QMap<int, WangId>())
{
}

void WangSet::addTile(Tile *tile, WangId wangId)
{
Q_ASSERT(tile->tileset() == mTileSet);

for (int i = 0; i < 4; ++i) {
Q_ASSERT(wangId.getColor(i,true) <= mEdgeColors);
}

for (int i = 0; i < 4; ++i) {
Q_ASSERT(wangId.getColor(i,false) <= mCornerColors);
}

mWangIdToTile.insert(wangId, tile);
mTileIdToWangId.insert(tile->id(), wangId);
}

Tile *WangSet::getMatchingTile(WangId wangId) const
{
auto potentials = getAllTiles(wangId);

if (potentials.length() > 0)
return potentials[qrand() % potentials.length()];
else
return NULL;
}

QList<Tile*> WangSet::getAllTiles(WangId wangId) const
{
QList<Tile*> list;

//Stores the space of a wild card, followed by how many colors that space can have.
QVector<QPoint> wildCards;
Copy link
Member

Choose a reason for hiding this comment

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

Please use a custom struct instead of QPoint for readability sake.


if (mEdgeColors > 0) {
for (int i = 0; i < 4; ++i) {
if (!wangId.getColor(i,true)) {
wildCards.append(QPoint(i * 8, mEdgeColors));
}
}
}

if (mCornerColors > 0) {
for (int i = 0; i < 4; ++i) {
if (!wangId.getColor(i,false)) {
wildCards.append(QPoint(i * 8 + 4, mCornerColors));
}
}
}

if (wildCards.isEmpty()) {
list.append(mWangIdToTile.values(wangId));
} else {
QStack<QPoint> stack;

for (int i = 0; i < wildCards.size(); ++i) {
stack.push(wildCards[i]);
}
Copy link
Member

Choose a reason for hiding this comment

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

Could use stack.append(wildCards) instead.


int max = wildCards.size();

while (!stack.isEmpty()) {
if (stack.size() == max) {
int idVariation = 0;

for (int i = 0; i < max; ++i) {
idVariation |= stack[i].y() << stack[i].x();
}
Copy link
Member

Choose a reason for hiding this comment

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

Coding style: please leave out the braces for one-line bodies (also below).


list.append(mWangIdToTile.values(idVariation | wangId.id()));

QPoint top = stack.pop();
top.setY(top.y() - 1);
if (top.y() > 0)
stack.push(top);
} else {
QPoint top = stack.pop();
top.setY(top.y() - 1);
if (top.y() > 0) {
stack.push(top);

for (int i = stack.size(); i < max; ++i) {
stack.push(wildCards[i]);
}
}
}
}
}

return list;
}

WangId WangSet::getWangIdOfTile(Tile *tile) const
{
if (tile->tileset() == mTileSet && mTileIdToWangId.contains(tile->id()))
Copy link
Member

Choose a reason for hiding this comment

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

These checks are not necessary, you can just return mTileIdToWangId.value(tile->id()), since when mTileIdToWangId does not contain the tile it will anyway return a default-constructed WangId.

return mTileIdToWangId.value(tile->id());
else
return WangId(0);
}
162 changes: 162 additions & 0 deletions src/libtiled/wangset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* wangset.h
* Copyright 2017, Benjamin Trotter <bdtrotte@ucsc.edu>
* This file is part of libtiled.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#include "tile.h"
#include "tileset.h"

#include <QMap>
#include <QMultiMap>
#include <QString>
#include <QList>

namespace Tiled {

class WangId
{
public:
WangId(unsigned id){ mId = id; }
WangId() { mId = 0; }
Copy link
Member

Choose a reason for hiding this comment

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

Coding style: please use the following notation to initialize members: WangId() : mId(0) {} (similarly for the constructor taking an id).


inline unsigned id() const { return mId; }
inline void setId(unsigned id) { mId = id; }
Copy link
Member

Choose a reason for hiding this comment

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

We could consider doing this instead:

operator unsigned() const { return mId; }

This way, we allow implicit conversion between WangId and unsigned in both directions (you already allow implicit conversion from unsigned to WangId by not marking the constructor as explicit).


/**
* @brief getColor returns the color of a desired edge/corner of a given wang id
Copy link
Member

Choose a reason for hiding this comment

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

Docs still need updating.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, for all the docs I just use qt's auto formatting. Though its a bit burdensome. Ill go through and update all those.

* @param index index 0-3 with zero being the top right, and 3 left top
* @param edges requesting edge color (corners if false)
* @return
*/
int getColor(int index, bool edges) const;
Copy link
Member

Choose a reason for hiding this comment

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

This method should really be split up in edgeColor(int index) and cornerColor(int index). It will be easier to read and perform slightly better.


/**
* @brief rotateWangId rotates the wang id 90 * rotations degrees ccw
Copy link
Member

Choose a reason for hiding this comment

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

Docs seem to mention old function name? I'd suggest to leave out the @brief and the function name.

* @param rotations 1-3
* @return
Copy link
Member

Choose a reason for hiding this comment

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

Returns nothing, so just leave out the @return.

*/
void rotate(int rotations);

//used in maping
bool operator <(const WangId w) const
{
return mId < w.id();
}

private:
unsigned mId;
};

inline int WangId::getColor(int index, bool edges) const
{
int shift = (index * 8) + ((!edges) * 4);

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

return color;
}

void WangId::rotate(int rotations)
Copy link
Member

Choose a reason for hiding this comment

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

Missing inline (but maybe should move to cpp file anyway).

{
if (rotations < 0)
rotations = 4 + (rotations % 4);
else
rotations %= 4;

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

mId = rotated;
}

/**
* Represents a wang set.
*/
class TILEDSHARED_EXPORT WangSet : public Object
{
public:
WangSet(Tileset *tileset,
int edgeColors,
int cornerColors,
QString name,
int imageTileId);

QString name() const { return mName; }
void setName(const QString &name) { mName = name; }

int imageTileId() const { return mImageTileId; }
void setImageTileId(int imageTileId) { mImageTileId = imageTileId; }

Tile *imageTile() const { return mTileSet->findTile(mImageTileId); }

int edgeColors() const { return mEdgeColors; }
int cornerColors() const { return mCornerColors; }
void setEdgeColors(int n) { mEdgeColors = n; }
void setCornerColors(int n) { mCornerColors = n; }

/**
* @brief addTile Adds a tile to the wang set
* @param tile
* @param wangId
*/
void addTile(Tile *tile, WangId wangId);

/**
* @brief getMatchingTile Returns a tile matching the given wangId.
* 0s in the id are wild cards, and can be filled with any color.
* If there are multiple possible options, one will be choosen at random.
* @param wangId
* @return
*/
Tile *getMatchingTile(WangId wangId) const;
Copy link
Member

Choose a reason for hiding this comment

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

Probably should be called findMatchingTile.


/**
* @brief getAllTiles Returns a list of all tiles which match a wangId
* 0s in the id are wild cards, and can be filled with any color.
* @param wangId
* @return
*/
QList<Tile*> getAllTiles(WangId wangId) const;
Copy link
Member

Choose a reason for hiding this comment

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

Probably should be called findMatchingTiles.



/**
* @brief wangIdOfTile returns the wangId of a given tileId
* @param tileId
Copy link
Member

Choose a reason for hiding this comment

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

All docs seem outdated. Also, if you don't provide any comment on a parameter, there is no need to mention it with @param.

*/
WangId getWangIdOfTile(Tile *tile) const;
Copy link
Member

Choose a reason for hiding this comment

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

Naming style: should be just wangIdOfTile.


private:
Tileset *mTileSet;
Copy link
Member

Choose a reason for hiding this comment

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

Naming: "tileset" is always a single word in Tiled source code, so this should should be mTileset.

QString mName;
int mImageTileId;
QMultiMap<WangId, Tile*> mWangIdToTile;
QMap<int, WangId> mTileIdToWangId; //This could be stored in the tile object.
Copy link
Member

Choose a reason for hiding this comment

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

Consider using a QHash instead, which has O(1) lookup rather than the O(log(n)) of QMap. The difference is equivalent with std::map vs. std::unordered_map.

int mEdgeColors;
int mCornerColors;
};

} // namespace Tiled