-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Wang Tiles #1582
Changes from 2 commits
904e8bc
cb8d9ae
e93cc74
c329a97
4757fb6
31689c6
e10151e
c7e67d0
0ef5add
74dbae3
400d47c
ff6c624
3916cd6
acae98a
68bd9af
52ae862
4398cea
7f58709
bb6b98a
0969d46
8b959a9
1df48f5
25f8494
888ea7b
825774a
0d3f353
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
|
||
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]); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use |
||
|
||
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(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These checks are not necessary, you can just return |
||
return mTileIdToWangId.value(tile->id()); | ||
else | ||
return WangId(0); | ||
} |
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; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Coding style: please use the following notation to initialize members: |
||
|
||
inline unsigned id() const { return mId; } | ||
inline void setId(unsigned id) { mId = id; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
||
/** | ||
* @brief getColor returns the color of a desired edge/corner of a given wang id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Docs still need updating. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method should really be split up in |
||
|
||
/** | ||
* @brief rotateWangId rotates the wang id 90 * rotations degrees ccw | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
* @param rotations 1-3 | ||
* @return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returns nothing, so just leave out the |
||
*/ | ||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing |
||
{ | ||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably should be called |
||
|
||
/** | ||
* @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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably should be called |
||
|
||
|
||
/** | ||
* @brief wangIdOfTile returns the wangId of a given tileId | ||
* @param tileId | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
*/ | ||
WangId getWangIdOfTile(Tile *tile) const; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naming style: should be just |
||
|
||
private: | ||
Tileset *mTileSet; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
QString mName; | ||
int mImageTileId; | ||
QMultiMap<WangId, Tile*> mWangIdToTile; | ||
QMap<int, WangId> mTileIdToWangId; //This could be stored in the tile object. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using a |
||
int mEdgeColors; | ||
int mCornerColors; | ||
}; | ||
|
||
} // namespace Tiled |
There was a problem hiding this comment.
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.