1 /*
2 * tileset.h
3 * Copyright 2008-2015, Thorbjørn Lindeijer <thorbjorn@lindeijer.nl>
4 * Copyright 2009, Edward Hutchins <eah1@yahoo.com>
5 *
6 * This file is part of libtiled.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21 * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #pragma once
31
32 #include "imagereference.h"
33 #include "object.h"
34
35 #include <QColor>
36 #include <QList>
37 #include <QPixmap>
38 #include <QPoint>
39 #include <QSharedPointer>
40 #include <QString>
41 #include <QVector>
42
43 #include <memory>
44
45 class QImage;
46
47 namespace Tiled {
48
49 class Tile;
50 class Tileset;
51 class WangSet;
52
53 typedef QSharedPointer<Tileset> SharedTileset;
54
55 /**
56 * A tileset, representing a set of tiles.
57 *
58 * This class is meant to be used by either loading tiles from a tileset image
59 * (using loadFromImage) or by adding/removing individual tiles (using
60 * addTile, insertTiles and removeTiles). These two use-cases are not meant to
61 * be mixed.
62 */
63 class TILEDSHARED_EXPORT Tileset : public Object
64 {
65 public:
66 /**
67 * The orientation of the tileset determines the projection used in the
68 * TileCollisionDock and for the Wang color overlay of the TilesetView.
69 */
70 enum Orientation {
71 Orthogonal,
72 Isometric,
73 };
74
75 /**
76 * Creates a new tileset with the given parameters. Using this function
77 * makes sure the internal weak pointer is initialized, which enables the
78 * sharedPointer() function.
79 *
80 * @param name the name of the tileset
81 * @param tileWidth the width of the tiles in the tileset
82 * @param tileHeight the height of the tiles in the tileset
83 * @param tileSpacing the spacing between the tiles in the tileset image
84 * @param margin the margin around the tiles in the tileset image
85 */
86 static SharedTileset create(const QString &name,
87 int tileWidth,
88 int tileHeight,
89 int tileSpacing = 0,
90 int margin = 0);
91
92 private:
93 /**
94 * Private constructor. Use create() instead.
95 */
96 Tileset(QString name, int tileWidth, int tileHeight,
97 int tileSpacing = 0, int margin = 0);
98
99 public:
100 QString exportFileName;
101 QString exportFormat;
102
103 ~Tileset();
104
105 const QString &name() const;
106 void setName(const QString &name);
107
108 const QString &fileName() const;
109 void setFileName(const QString &fileName);
110 bool isExternal() const;
111
112 void setFormat(const QString &format);
113 QString format() const;
114
115 int tileWidth() const;
116 int tileHeight() const;
117
118 QSize tileSize() const;
119 void setTileSize(QSize tileSize);
120
121 int tileSpacing() const;
122 void setTileSpacing(int tileSpacing);
123
124 int margin() const;
125 void setMargin(int margin);
126
127 Alignment objectAlignment() const;
128 void setObjectAlignment(Alignment objectAlignment);
129
130 QPoint tileOffset() const;
131 void setTileOffset(QPoint offset);
132
133 Orientation orientation() const;
134 void setOrientation(Orientation orientation);
135
136 QSize gridSize() const;
137 void setGridSize(QSize gridSize);
138
139 const QMap<int, Tile*> &tilesById() const;
140 const QList<Tile*> &tiles() const;
141 inline Tile *findTile(int id) const;
tileAt(int id)142 Tile *tileAt(int id) const { return findTile(id); } // provided for Python
143 int findTileLocation(Tile *tile) const;
144 Tile *findOrCreateTile(int id);
145 int tileCount() const;
146
147 int columnCount() const;
148 int rowCount() const;
149 void setColumnCount(int columnCount);
150 int expectedColumnCount() const;
151 int expectedRowCount() const;
152 void syncExpectedColumnsAndRows();
153
154 int imageWidth() const;
155 int imageHeight() const;
156
157 QColor transparentColor() const;
158 void setTransparentColor(const QColor &c);
159
160 const QColor &backgroundColor() const;
161 void setBackgroundColor(QColor color);
162
163 void setImageReference(const ImageReference &reference);
164
165 bool loadFromImage(const QImage &image, const QUrl &source);
166 bool loadFromImage(const QImage &image, const QString &source);
167 bool loadFromImage(const QString &fileName);
168 bool loadImage();
169
170 SharedTileset findSimilarTileset(const QVector<SharedTileset> &tilesets) const;
171
172 const QUrl &imageSource() const;
173 void setImageSource(const QUrl &imageSource);
174 void setImageSource(const QString &url);
175 QString imageSourceString() const;
176
177 bool isCollection() const;
178
179 int columnCountForWidth(int width) const;
180 int rowCountForHeight(int height) const;
181
182 const QList<WangSet*> &wangSets() const;
183 int wangSetCount() const;
184 WangSet *wangSet(int index) const;
185
186 void addWangSet(std::unique_ptr<WangSet> wangSet);
187 void insertWangSet(int index, std::unique_ptr<WangSet> wangSet);
188 std::unique_ptr<WangSet> takeWangSetAt(int index);
189
190 Tile *addTile(const QPixmap &image, const QUrl &source = QUrl());
191 void addTiles(const QList<Tile*> &tiles);
192 void removeTiles(const QList<Tile *> &tiles);
193 void deleteTile(int id);
194 QList<int> relocateTiles(const QList<Tile *> &tiles, int location);
195
196 bool anyTileOutOfOrder() const;
197
198 void setNextTileId(int nextId);
199 int nextTileId() const;
200 int takeNextTileId();
201
202 void setTileImage(Tile *tile,
203 const QPixmap &image,
204 const QUrl &source = QUrl());
205
206 SharedTileset sharedPointer() const;
207
208 void setOriginalTileset(const SharedTileset &original);
209 SharedTileset originalTileset() const;
210
211 void setStatus(LoadingStatus status);
212 void setImageStatus(LoadingStatus status);
213 LoadingStatus status() const;
214 LoadingStatus imageStatus() const;
215
216 enum TransformationFlag {
217 NoTransformation = 0,
218 AllowFlipHorizontally = 1 << 0,
219 AllowFlipVertically = 1 << 1,
220 AllowRotate = 1 << 2,
221 PreferUntransformed = 1 << 3,
222 };
223 Q_DECLARE_FLAGS(TransformationFlags, TransformationFlag)
224
225 TransformationFlags transformationFlags() const;
226 void setTransformationFlags(TransformationFlags flags);
227
228 void swap(Tileset &other);
229
230 SharedTileset clone() const;
231
232 /**
233 * Helper function that converts the tileset orientation to a string value.
234 * Useful for map writers.
235 *
236 * @return The tileset orientation as a lowercase string.
237 */
238 static QString orientationToString(Orientation);
239
240 /**
241 * Helper function that converts a string to a tileset orientation enumerator.
242 * Useful for map readers.
243 *
244 * @return The tileset orientation matching the given string, or
245 * Tileset::Orthogonal if the string is unrecognized.
246 */
247 static Orientation orientationFromString(const QString &);
248
249 private:
250 void updateTileSize();
251
252 QString mName;
253 QString mFileName;
254 ImageReference mImageReference;
255 int mTileWidth;
256 int mTileHeight;
257 int mTileSpacing;
258 int mMargin;
259 QPoint mTileOffset;
260 Alignment mObjectAlignment;
261 Orientation mOrientation;
262 QSize mGridSize;
263 int mColumnCount;
264 int mExpectedColumnCount;
265 int mExpectedRowCount;
266 int mNextTileId;
267 QMap<int, Tile*> mTilesById;
268 QList<Tile*> mTiles;
269 QList<WangSet*> mWangSets;
270 LoadingStatus mStatus;
271 QColor mBackgroundColor;
272 QString mFormat;
273 TransformationFlags mTransformationFlags;
274
275 QWeakPointer<Tileset> mWeakPointer;
276 QWeakPointer<Tileset> mOriginalTileset;
277 };
278
279
280 /**
281 * Returns the name of this tileset.
282 */
name()283 inline const QString &Tileset::name() const
284 {
285 return mName;
286 }
287
288 /**
289 * Sets the name of this tileset.
290 */
setName(const QString & name)291 inline void Tileset::setName(const QString &name)
292 {
293 mName = name;
294 }
295
296 /**
297 * Returns the file name of this tileset. When the tileset isn't an
298 * external tileset, the file name is empty.
299 */
fileName()300 inline const QString &Tileset::fileName() const
301 {
302 return mFileName;
303 }
304
305 /**
306 * Sets the filename of this tileset.
307 */
setFileName(const QString & fileName)308 inline void Tileset::setFileName(const QString &fileName)
309 {
310 mFileName = fileName;
311 }
312
313 /**
314 * Returns whether this tileset is external.
315 */
isExternal()316 inline bool Tileset::isExternal() const
317 {
318 return !mFileName.isEmpty();
319 }
320
321 /**
322 * Returns the maximum width of the tiles in this tileset.
323 */
tileWidth()324 inline int Tileset::tileWidth() const
325 {
326 return mTileWidth;
327 }
328
329 /**
330 * Returns the maximum height of the tiles in this tileset.
331 */
tileHeight()332 inline int Tileset::tileHeight() const
333 {
334 return mTileHeight;
335 }
336
337 /**
338 * Returns the maximum size of the tiles in this tileset.
339 */
tileSize()340 inline QSize Tileset::tileSize() const
341 {
342 return QSize(mTileWidth, mTileHeight);
343 }
344
345 /**
346 * Returns the spacing between the tiles in the tileset image.
347 */
tileSpacing()348 inline int Tileset::tileSpacing() const
349 {
350 return mTileSpacing;
351 }
352
353 /**
354 * Returns the margin around the tiles in the tileset image.
355 */
margin()356 inline int Tileset::margin() const
357 {
358 return mMargin;
359 }
360
361 /**
362 * Returns the alignment to use for tile objects.
363 */
objectAlignment()364 inline Alignment Tileset::objectAlignment() const
365 {
366 return mObjectAlignment;
367 }
368
369 /**
370 * @see objectAlignment
371 */
setObjectAlignment(Alignment objectAlignment)372 inline void Tileset::setObjectAlignment(Alignment objectAlignment)
373 {
374 mObjectAlignment = objectAlignment;
375 }
376
377 /**
378 * Returns the offset that is applied when drawing the tiles in this
379 * tileset.
380 */
tileOffset()381 inline QPoint Tileset::tileOffset() const
382 {
383 return mTileOffset;
384 }
385
386 /**
387 * @see tileOffset
388 */
setTileOffset(QPoint offset)389 inline void Tileset::setTileOffset(QPoint offset)
390 {
391 mTileOffset = offset;
392 }
393
394 /**
395 * Returns the orientation of the tiles in this tileset.
396 */
orientation()397 inline Tileset::Orientation Tileset::orientation() const
398 {
399 return mOrientation;
400 }
401
402 /**
403 * @see orientation
404 */
setOrientation(Orientation orientation)405 inline void Tileset::setOrientation(Orientation orientation)
406 {
407 mOrientation = orientation;
408 }
409
410 /**
411 * Returns the grid size that is used when the tileset has Isometric
412 * orientation.
413 */
gridSize()414 inline QSize Tileset::gridSize() const
415 {
416 return mGridSize;
417 }
418
419 /**
420 * @see gridSize
421 */
setGridSize(QSize gridSize)422 inline void Tileset::setGridSize(QSize gridSize)
423 {
424 mGridSize = gridSize;
425 }
426
tilesById()427 inline const QMap<int, Tile *> &Tileset::tilesById() const
428 {
429 return mTilesById;
430 }
431
432 /**
433 * Returns a const reference to the tiles in this tileset.
434 */
tiles()435 inline const QList<Tile*> &Tileset::tiles() const
436 {
437 return mTiles;
438 }
439
440 /**
441 * Returns the tile with the given tile ID. The tile IDs are local to this
442 * tileset.
443 */
findTile(int id)444 inline Tile *Tileset::findTile(int id) const
445 {
446 return mTilesById.value(id);
447 }
448
449 /**
450 * Returns the number of tiles in this tileset.
451 *
452 * Note that the tiles are not necessarily consecutive.
453 */
tileCount()454 inline int Tileset::tileCount() const
455 {
456 return mTiles.size();
457 }
458
459 /**
460 * Returns the number of tile columns in the tileset image.
461 */
columnCount()462 inline int Tileset::columnCount() const
463 {
464 return mColumnCount;
465 }
466
467 /**
468 * Sets the column count to use when displaying this tileset. For tileset image
469 * based tilesets, this reflects the number of tile columns in the image.
470 */
setColumnCount(int columnCount)471 inline void Tileset::setColumnCount(int columnCount)
472 {
473 mColumnCount = columnCount;
474 }
475
476 /**
477 * Returns the number of tile columns expected to be in the tileset image. This
478 * may differ from the actual amount of columns encountered when loading the
479 * image, and can be used for automatically adjusting tile indexes.
480 */
expectedColumnCount()481 inline int Tileset::expectedColumnCount() const
482 {
483 return mExpectedColumnCount;
484 }
485
486 /**
487 * Returns the number of tile rows expected to be in the tileset image. This
488 * may differ from the actual amount of rows encountered when loading the
489 * image, and is checked when automatically adjusting tile indexes.
490 */
expectedRowCount()491 inline int Tileset::expectedRowCount() const
492 {
493 return mExpectedRowCount;
494 }
495
496 /**
497 * Sets the expected column and row count to the actual column count. Usually
498 * called after checking with the user whether he wants the map to be adjusted
499 * to a change to the tileset image size.
500 */
syncExpectedColumnsAndRows()501 inline void Tileset::syncExpectedColumnsAndRows()
502 {
503 mExpectedColumnCount = mColumnCount;
504 mExpectedRowCount = rowCount();
505 }
506
507 /**
508 * Returns the width of the tileset image.
509 */
imageWidth()510 inline int Tileset::imageWidth() const
511 {
512 return mImageReference.size.width();
513 }
514
515 /**
516 * Returns the height of the tileset image.
517 */
imageHeight()518 inline int Tileset::imageHeight() const
519 {
520 return mImageReference.size.height();
521 }
522
523 /**
524 * Returns the transparent color, or an invalid color if no transparent
525 * color is used.
526 */
transparentColor()527 inline QColor Tileset::transparentColor() const
528 {
529 return mImageReference.transparentColor;
530 }
531
532 /**
533 * Returns the background color of this tileset.
534 */
backgroundColor()535 inline const QColor &Tileset::backgroundColor() const
536 {
537 return mBackgroundColor;
538 }
539
540 /**
541 * Sets the background color of this tileset.
542 */
setBackgroundColor(QColor color)543 inline void Tileset::setBackgroundColor(QColor color)
544 {
545 mBackgroundColor = color;
546 }
547
548 /**
549 * Returns the URL of the external image that contains the tiles in
550 * this tileset. Is an empty string when this tileset doesn't have a
551 * tileset image.
552 */
imageSource()553 inline const QUrl &Tileset::imageSource() const
554 {
555 return mImageReference.source;
556 }
557
558 /**
559 * QString-API for Python.
560 */
imageSourceString()561 inline QString Tileset::imageSourceString() const
562 {
563 const QUrl &url = imageSource();
564 return url.isLocalFile() ? url.toLocalFile() : url.toString();
565 }
566
567 /**
568 * Returns whether this tileset is a collection of images. In this case, the
569 * tileset itself has no image source.
570 */
isCollection()571 inline bool Tileset::isCollection() const
572 {
573 return imageSource().isEmpty();
574 }
575
wangSets()576 inline const QList<WangSet*> &Tileset::wangSets() const
577 {
578 return mWangSets;
579 }
580
wangSetCount()581 inline int Tileset::wangSetCount() const
582 {
583 return mWangSets.size();
584 }
585
wangSet(int index)586 inline WangSet *Tileset::wangSet(int index) const
587 {
588 return index >= 0 ? mWangSets[index] : nullptr;
589 }
590
591 /**
592 * Sets the next id to be used for tiles in this tileset.
593 */
setNextTileId(int nextId)594 inline void Tileset::setNextTileId(int nextId)
595 {
596 Q_ASSERT(nextId > 0);
597 mNextTileId = nextId;
598 }
599
600 /**
601 * Returns the next tile id for this tileset.
602 */
nextTileId()603 inline int Tileset::nextTileId() const
604 {
605 return mNextTileId;
606 }
607
608 /**
609 * Returns the next tile id for this tileset and allocates a new one.
610 */
takeNextTileId()611 inline int Tileset::takeNextTileId()
612 {
613 return mNextTileId++;
614 }
615
sharedPointer()616 inline SharedTileset Tileset::sharedPointer() const
617 {
618 return SharedTileset(mWeakPointer);
619 }
620
621 /**
622 * Sets the status of this tileset.
623 */
setStatus(LoadingStatus status)624 inline void Tileset::setStatus(LoadingStatus status)
625 {
626 mStatus = status;
627 }
628
629 /**
630 * Sets the loading status of this tileset's image.
631 */
setImageStatus(LoadingStatus status)632 inline void Tileset::setImageStatus(LoadingStatus status)
633 {
634 mImageReference.status = status;
635 }
636
637 /**
638 * Returns the loading status of this tileset.
639 *
640 * Only valid for external tilesets (fileName() != empty).
641 */
status()642 inline LoadingStatus Tileset::status() const
643 {
644 return mStatus;
645 }
646
647 /**
648 * Returns the loading status of this tileset's image.
649 *
650 * Only valid for tilesets based on a single image (imageSource() != empty).
651 */
imageStatus()652 inline LoadingStatus Tileset::imageStatus() const
653 {
654 return mImageReference.status;
655 }
656
transformationFlags()657 inline Tileset::TransformationFlags Tileset::transformationFlags() const
658 {
659 return mTransformationFlags;
660 }
661
setTransformationFlags(TransformationFlags flags)662 inline void Tileset::setTransformationFlags(TransformationFlags flags)
663 {
664 mTransformationFlags = flags;
665 }
666
667 } // namespace Tiled
668
669 Q_DECLARE_METATYPE(Tiled::Tileset*)
670 Q_DECLARE_METATYPE(Tiled::SharedTileset)
671
672 Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::Tileset::TransformationFlags)
673