1 /*
2 * map.h
3 * Copyright 2008-2010, Thorbjørn Lindeijer <thorbjorn@lindeijer.nl>
4 * Copyright 2008, Roderic Morris <roderic@ccs.neu.edu>
5 * Copyright 2010, Andrew G. Crowell <overkill9999@gmail.com>
6 *
7 * This file is part of libtiled.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
22 * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #pragma once
32
33 #include "layer.h"
34 #include "object.h"
35 #include "tileset.h"
36
37 #include <QColor>
38 #include <QList>
39 #include <QMargins>
40 #include <QSharedPointer>
41 #include <QSize>
42 #include <QVector>
43
44 #include <memory>
45
46 namespace Tiled {
47
48 class MapObject;
49 class ObjectGroup;
50 class ObjectTemplate;
51 class Tile;
52
53 /**
54 * A tile map. Consists of a stack of layers.
55 *
56 * It also keeps track of the list of referenced tilesets.
57 */
58 class TILEDSHARED_EXPORT Map : public Object
59 {
60 class LayerIteratorHelper
61 {
62 public:
63 LayerIteratorHelper(const Map &map, int layerTypes);
64
65 LayerIterator begin() const;
66 LayerIterator end() const;
67 bool isEmpty() const;
68
69 private:
70 const Map &mMap;
71 const int mLayerTypes;
72 };
73
74 public:
75 QString fileName;
76 QString exportFileName;
77 QString exportFormat;
78
79 enum Property {
80 TileWidthProperty,
81 TileHeightProperty,
82 InfiniteProperty,
83 HexSideLengthProperty,
84 StaggerAxisProperty,
85 StaggerIndexProperty,
86 OrientationProperty,
87 RenderOrderProperty,
88 BackgroundColorProperty,
89 LayerDataFormatProperty,
90 CompressionLevelProperty,
91 ChunkSizeProperty
92 };
93
94 /**
95 * The orientation of the map determines how it should be rendered. An
96 * Orthogonal map is using rectangular tiles that are aligned on a
97 * straight grid. An Isometric map uses diamond shaped tiles that are
98 * aligned on an isometric projected grid. A Hexagonal map uses hexagon
99 * shaped tiles that fit into each other by shifting every other row.
100 */
101 enum Orientation {
102 Unknown,
103 Orthogonal,
104 Isometric,
105 Staggered,
106 Hexagonal
107 };
108
109 /**
110 * The different formats in which the tile layer data can be stored.
111 */
112 enum LayerDataFormat {
113 XML = 0,
114 Base64 = 1,
115 Base64Gzip = 2,
116 Base64Zlib = 3,
117 Base64Zstandard = 4,
118 CSV = 5
119 };
120
121 /**
122 * The order in which tiles are rendered on screen.
123 */
124 enum RenderOrder {
125 RightDown = 0,
126 RightUp = 1,
127 LeftDown = 2,
128 LeftUp = 3
129 };
130
131 /**
132 * Which axis is staggered. Only used by the isometric staggered and
133 * hexagonal map renderers.
134 */
135 enum StaggerAxis {
136 StaggerX,
137 StaggerY
138 };
139
140 /**
141 * When staggering, specifies whether the odd or the even rows/columns are
142 * shifted half a tile right/down. Only used by the isometric staggered and
143 * hexagonal map renderers.
144 */
145 enum StaggerIndex {
146 StaggerOdd = 0,
147 StaggerEven = 1
148 };
149
150 struct Parameters
151 {
152 Orientation orientation = Orthogonal;
153 RenderOrder renderOrder = RightDown;
154 int width = 0;
155 int height = 0;
156 int tileWidth = 0;
157 int tileHeight = 0;
158 bool infinite = false;
159 int hexSideLength = 0;
160 StaggerAxis staggerAxis = StaggerY;
161 StaggerIndex staggerIndex = StaggerOdd;
162 QColor backgroundColor;
163 };
164
165 struct EditorSettings
166 {
167 int compressionLevel = -1;
168 QSize chunkSize = QSize(CHUNK_SIZE, CHUNK_SIZE);
169 LayerDataFormat layerDataFormat = Base64Zlib;
170 };
171
172 Map();
173 Map(const Parameters ¶meters);
174
175 /**
176 * Constructor taking map orientation, size and tile size as parameters.
177 *
178 * @deprecated Only kept around for the Python API!
179 */
180 Map(Orientation orientation,
181 int width, int height,
182 int tileWidth, int tileHeight);
183
184 ~Map();
185
186 const Parameters ¶meters() const;
187
188 Orientation orientation() const;
189 void setOrientation(Orientation orientation);
190
191 RenderOrder renderOrder() const;
192 void setRenderOrder(RenderOrder renderOrder);
193
194 int compressionLevel() const;
195 void setCompressionLevel(int compressionLevel);
196
197 int width() const;
198 void setWidth(int width);
199
200 int height() const;
201 void setHeight(int height);
202
203 QSize size() const;
204
205 int tileWidth() const;
206 void setTileWidth(int width);
207
208 int tileHeight() const;
209 void setTileHeight(int height);
210
211 QSize tileSize() const;
212
213 bool infinite() const;
214 void setInfinite(bool infinite);
215
216 int hexSideLength() const;
217 void setHexSideLength(int hexSideLength);
218
219 StaggerAxis staggerAxis() const;
220 void setStaggerAxis(StaggerAxis staggerAxis);
221
222 StaggerIndex staggerIndex() const;
223 void setStaggerIndex(StaggerIndex staggerIndex);
224 void invertStaggerIndex();
225
226 QMargins drawMargins() const;
227 void invalidateDrawMargins();
228
229 QMargins computeLayerOffsetMargins() const;
230
231 int layerCount() const;
232 int layerCount(Layer::TypeFlag type) const;
233
234 int tileLayerCount() const;
235 int objectGroupCount() const;
236 int imageLayerCount() const;
237 int groupLayerCount() const;
238
239 Layer *layerAt(int index) const;
240
241 const QList<Layer*> &layers() const;
242
243 LayerIteratorHelper allLayers(int layerTypes = Layer::AnyLayerType) const;
244 LayerIteratorHelper tileLayers() const;
245 LayerIteratorHelper objectGroups() const;
246
247 void addLayer(std::unique_ptr<Layer> layer);
248 void addLayer(Layer *layer);
249
250 int indexOfLayer(const QString &layerName,
251 int layerTypes = Layer::AnyLayerType) const;
252
253 Layer *findLayer(const QString &name,
254 int layerTypes = Layer::AnyLayerType) const;
255
256 void insertLayer(int index, Layer *layer);
257
258 Layer *takeLayerAt(int index);
259
260 bool addTileset(const SharedTileset &tileset);
261 void addTilesets(const QSet<SharedTileset> &tilesets);
262 void insertTileset(int index, const SharedTileset &tileset);
263
264 int indexOfTileset(const SharedTileset &tileset) const;
265
266 void removeTilesetAt(int index);
267
268 bool replaceTileset(const SharedTileset &oldTileset,
269 const SharedTileset &newTileset);
270
271 int tilesetCount() const;
272 SharedTileset tilesetAt(int index) const;
273 const QVector<SharedTileset> &tilesets() const;
274
275 QSet<SharedTileset> usedTilesets() const;
276
277 QList<MapObject*> replaceObjectTemplate(const ObjectTemplate *oldObjectTemplate,
278 const ObjectTemplate *newObjectTemplate);
279
280 const QColor &backgroundColor() const;
281 void setBackgroundColor(QColor color);
282
283 QSize chunkSize() const;
284 void setChunkSize(QSize size);
285
286 bool isTilesetUsed(const Tileset *tileset) const;
287
288 std::unique_ptr<Map> clone() const;
289
290 void copyLayers(const QList<Layer*> &layers,
291 const QRegion &tileRegion,
292 Map &targetMap) const;
293
294 void normalizeTileLayerPositionsAndMapSize();
295
296 bool isStaggered() const;
297
298 LayerDataFormat layerDataFormat() const;
299 void setLayerDataFormat(LayerDataFormat format);
300
301 void setNextLayerId(int nextId);
302 int nextLayerId() const;
303 int takeNextLayerId();
304
305 void setNextObjectId(int nextId);
306 int nextObjectId() const;
307 int takeNextObjectId();
308 void initializeObjectIds(ObjectGroup &objectGroup);
309
310 Layer *findLayerById(int layerId) const;
311 MapObject *findObjectById(int objectId) const;
312
313 QRegion tileRegion() const;
314
315 private:
316 friend class GroupLayer; // so it can call adoptLayer
317
318 void adoptLayer(Layer &layer);
319
320 void recomputeDrawMargins() const;
321
322 Parameters mParameters;
323 EditorSettings mEditorSettings;
324
325 mutable QMargins mDrawMargins;
326 mutable bool mDrawMarginsDirty = true;
327
328 QList<Layer*> mLayers;
329 QVector<SharedTileset> mTilesets;
330
331 int mNextLayerId = 1;
332 int mNextObjectId = 1;
333 };
334
335
parameters()336 inline const Map::Parameters &Map::parameters() const
337 {
338 return mParameters;
339 }
340
orientation()341 inline Map::Orientation Map::orientation() const
342 {
343 return mParameters.orientation;
344 }
345
setOrientation(Map::Orientation orientation)346 inline void Map::setOrientation(Map::Orientation orientation)
347 {
348 mParameters.orientation = orientation;
349 }
350
renderOrder()351 inline Map::RenderOrder Map::renderOrder() const
352 {
353 return mParameters.renderOrder;
354 }
355
setRenderOrder(Map::RenderOrder renderOrder)356 inline void Map::setRenderOrder(Map::RenderOrder renderOrder)
357 {
358 mParameters.renderOrder = renderOrder;
359 }
360
361 /**
362 * Returns the compression level used for compressed tile layer data.
363 */
compressionLevel()364 inline int Map::compressionLevel() const
365 {
366 return mEditorSettings.compressionLevel;
367 }
368
setCompressionLevel(int compressionLevel)369 inline void Map::setCompressionLevel(int compressionLevel)
370 {
371 mEditorSettings.compressionLevel = compressionLevel;
372 }
373
374 /**
375 * Returns the width of this map in tiles.
376 */
width()377 inline int Map::width() const
378 {
379 return mParameters.width;
380 }
381
382 /**
383 * Sets the width of this map in tiles.
384 */
setWidth(int width)385 inline void Map::setWidth(int width)
386 {
387 mParameters.width = width;
388 }
389
390 /**
391 * Returns the height of this map in tiles.
392 */
height()393 inline int Map::height() const
394 {
395 return mParameters.height;
396 }
397
398 /**
399 * Sets the height of this map in tiles.
400 */
setHeight(int height)401 inline void Map::setHeight(int height)
402 {
403 mParameters.height = height;
404 }
405
406 /**
407 * Returns the size of this map. Provided for convenience.
408 */
size()409 inline QSize Map::size() const
410 {
411 return QSize(mParameters.width, mParameters.height);
412 }
413
414 /**
415 * Returns the tile width of this map.
416 */
tileWidth()417 inline int Map::tileWidth() const
418 {
419 return mParameters.tileWidth;
420 }
421
422 /**
423 * Sets the width of one tile.
424 */
setTileWidth(int width)425 inline void Map::setTileWidth(int width)
426 {
427 mParameters.tileWidth = width;
428 }
429
430 /**
431 * Returns the tile height used by this map.
432 */
tileHeight()433 inline int Map::tileHeight() const
434 {
435 return mParameters.tileHeight;
436 }
437
438 /**
439 * Sets the height of one tile.
440 */
setTileHeight(int height)441 inline void Map::setTileHeight(int height)
442 {
443 mParameters.tileHeight = height;
444 }
445
446 /**
447 * Returns the size of one tile. Provided for convenience.
448 */
tileSize()449 inline QSize Map::tileSize() const
450 {
451 return QSize(mParameters.tileWidth, mParameters.tileHeight);
452 }
453
infinite()454 inline bool Map::infinite() const
455 {
456 return mParameters.infinite;
457 }
458
setInfinite(bool infinite)459 inline void Map::setInfinite(bool infinite)
460 {
461 mParameters.infinite = infinite;
462 }
463
hexSideLength()464 inline int Map::hexSideLength() const
465 {
466 return mParameters.hexSideLength;
467 }
468
setHexSideLength(int hexSideLength)469 inline void Map::setHexSideLength(int hexSideLength)
470 {
471 mParameters.hexSideLength = hexSideLength;
472 }
473
staggerAxis()474 inline Map::StaggerAxis Map::staggerAxis() const
475 {
476 return mParameters.staggerAxis;
477 }
478
setStaggerAxis(StaggerAxis staggerAxis)479 inline void Map::setStaggerAxis(StaggerAxis staggerAxis)
480 {
481 mParameters.staggerAxis = staggerAxis;
482 }
483
staggerIndex()484 inline Map::StaggerIndex Map::staggerIndex() const
485 {
486 return mParameters.staggerIndex;
487 }
488
setStaggerIndex(StaggerIndex staggerIndex)489 inline void Map::setStaggerIndex(StaggerIndex staggerIndex)
490 {
491 mParameters.staggerIndex = staggerIndex;
492 }
493
invertStaggerIndex()494 inline void Map::invertStaggerIndex()
495 {
496 mParameters.staggerIndex = static_cast<StaggerIndex>(!mParameters.staggerIndex);
497 }
498
invalidateDrawMargins()499 inline void Map::invalidateDrawMargins()
500 {
501 mDrawMarginsDirty = true;
502 }
503
504 /**
505 * Returns the number of layers of this map.
506 */
layerCount()507 inline int Map::layerCount() const
508 {
509 return mLayers.size();
510 }
511
tileLayerCount()512 inline int Map::tileLayerCount() const
513 {
514 return layerCount(Layer::TileLayerType);
515 }
516
objectGroupCount()517 inline int Map::objectGroupCount() const
518 {
519 return layerCount(Layer::ObjectGroupType);
520 }
521
imageLayerCount()522 inline int Map::imageLayerCount() const
523 {
524 return layerCount(Layer::ImageLayerType);
525 }
526
groupLayerCount()527 inline int Map::groupLayerCount() const
528 {
529 return layerCount(Layer::GroupLayerType);
530 }
531
532 /**
533 * Returns the top-level layer at the specified \a index.
534 */
layerAt(int index)535 inline Layer *Map::layerAt(int index) const
536 {
537 return mLayers.at(index);
538 }
539
540 /**
541 * Returns the list of top-level layers of this map.
542 */
layers()543 inline const QList<Layer *> &Map::layers() const
544 {
545 return mLayers;
546 }
547
548 /**
549 * Returns a helper for iterating all tile layers of the given \a layerTypes
550 * in this map.
551 */
allLayers(int layerTypes)552 inline Map::LayerIteratorHelper Map::allLayers(int layerTypes) const
553 {
554 return LayerIteratorHelper { *this, layerTypes };
555 }
556
557 /**
558 * Returns a helper for iterating all tile layers in this map.
559 */
tileLayers()560 inline Map::LayerIteratorHelper Map::tileLayers() const
561 {
562 return allLayers(Layer::TileLayerType);
563 }
564
565 /**
566 * Returns a helper for iterating all object groups in this map.
567 */
objectGroups()568 inline Map::LayerIteratorHelper Map::objectGroups() const
569 {
570 return allLayers(Layer::ObjectGroupType);
571 }
572
573 /**
574 * Adds a layer to this map.
575 */
addLayer(std::unique_ptr<Layer> layer)576 inline void Map::addLayer(std::unique_ptr<Layer> layer)
577 {
578 addLayer(layer.release());
579 }
580
581 /**
582 * Returns the number of tilesets of this map.
583 */
tilesetCount()584 inline int Map::tilesetCount() const
585 {
586 return mTilesets.size();
587 }
588
589 /**
590 * Returns the tileset at the given index.
591 */
tilesetAt(int index)592 inline SharedTileset Map::tilesetAt(int index) const
593 {
594 return mTilesets.at(index);
595 }
596
597 /**
598 * Returns the tilesets that have been added to this map.
599 */
tilesets()600 inline const QVector<SharedTileset> &Map::tilesets() const
601 {
602 return mTilesets;
603 }
604
605 /**
606 * Returns the background color of this map.
607 */
backgroundColor()608 inline const QColor &Map::backgroundColor() const
609 {
610 return mParameters.backgroundColor;
611 }
612
setBackgroundColor(QColor color)613 inline void Map::setBackgroundColor(QColor color)
614 {
615 mParameters.backgroundColor = color;
616 }
617
618 /**
619 * Returns the chunk size used when saving tile layers of this map.
620 */
chunkSize()621 inline QSize Map::chunkSize() const
622 {
623 return mEditorSettings.chunkSize;
624 }
625
setChunkSize(QSize size)626 inline void Map::setChunkSize(QSize size)
627 {
628 mEditorSettings.chunkSize = size;
629 }
630
631 /**
632 * Returns whether the map is staggered.
633 */
isStaggered()634 inline bool Map::isStaggered() const
635 {
636 return orientation() == Hexagonal || orientation() == Staggered;
637 }
638
layerDataFormat()639 inline Map::LayerDataFormat Map::layerDataFormat() const
640 {
641 return mEditorSettings.layerDataFormat;
642 }
643
setLayerDataFormat(Map::LayerDataFormat format)644 inline void Map::setLayerDataFormat(Map::LayerDataFormat format)
645 {
646 mEditorSettings.layerDataFormat = format;
647 }
648
649 /**
650 * Sets the next id to be used for layers of this map.
651 */
setNextLayerId(int nextId)652 inline void Map::setNextLayerId(int nextId)
653 {
654 Q_ASSERT(nextId > 0);
655 mNextLayerId = nextId;
656 }
657
658 /**
659 * Returns the next layer id for this map.
660 */
nextLayerId()661 inline int Map::nextLayerId() const
662 {
663 return mNextLayerId;
664 }
665
666 /**
667 * Returns the next layer id for this map and allocates a new one.
668 */
takeNextLayerId()669 inline int Map::takeNextLayerId()
670 {
671 return mNextLayerId++;
672 }
673
674 /**
675 * Sets the next id to be used for objects on this map.
676 */
setNextObjectId(int nextId)677 inline void Map::setNextObjectId(int nextId)
678 {
679 Q_ASSERT(nextId > 0);
680 mNextObjectId = nextId;
681 }
682
683 /**
684 * Returns the next object id for this map.
685 */
nextObjectId()686 inline int Map::nextObjectId() const
687 {
688 return mNextObjectId;
689 }
690
691 /**
692 * Returns the next object id for this map and allocates a new one.
693 */
takeNextObjectId()694 inline int Map::takeNextObjectId()
695 {
696 return mNextObjectId++;
697 }
698
699
LayerIteratorHelper(const Map & map,int layerTypes)700 inline Map::LayerIteratorHelper::LayerIteratorHelper(const Map &map, int layerTypes)
701 : mMap(map)
702 , mLayerTypes(layerTypes)
703 {}
704
begin()705 inline LayerIterator Map::LayerIteratorHelper::begin() const
706 {
707 LayerIterator iterator(&mMap, mLayerTypes);
708 iterator.next();
709 return iterator;
710 }
711
end()712 inline LayerIterator Map::LayerIteratorHelper::end() const
713 {
714 LayerIterator iterator(&mMap, mLayerTypes);
715 iterator.toBack();
716 return iterator;
717 }
718
isEmpty()719 inline bool Map::LayerIteratorHelper::isEmpty() const
720 {
721 return LayerIterator(&mMap, mLayerTypes).next() == nullptr;
722 }
723
724
725 TILEDSHARED_EXPORT QString staggerAxisToString(Map::StaggerAxis);
726 TILEDSHARED_EXPORT Map::StaggerAxis staggerAxisFromString(const QString &);
727
728 TILEDSHARED_EXPORT QString staggerIndexToString(Map::StaggerIndex staggerIndex);
729 TILEDSHARED_EXPORT Map::StaggerIndex staggerIndexFromString(const QString &);
730
731 /**
732 * Helper function that converts the map orientation to a string value. Useful
733 * for map writers.
734 *
735 * @return The map orientation as a lowercase string.
736 */
737 TILEDSHARED_EXPORT QString orientationToString(Map::Orientation);
738
739 /**
740 * Helper function that converts a string to a map orientation enumerator.
741 * Useful for map readers.
742 *
743 * @return The map orientation matching the given string, or Map::Unknown if
744 * the string is unrecognized.
745 */
746 TILEDSHARED_EXPORT Map::Orientation orientationFromString(const QString &);
747
748 /**
749 * Helper function that returns a string representing the compression used by
750 * the given layer data format.
751 *
752 * @return The compression as a lowercase string.
753 */
754 TILEDSHARED_EXPORT QString compressionToString(Map::LayerDataFormat);
755
756 TILEDSHARED_EXPORT QString renderOrderToString(Map::RenderOrder renderOrder);
757 TILEDSHARED_EXPORT Map::RenderOrder renderOrderFromString(const QString &);
758
759 typedef QSharedPointer<Map> SharedMap;
760
761 } // namespace Tiled
762
763 Q_DECLARE_METATYPE(Tiled::Map*)
764 Q_DECLARE_METATYPE(Tiled::Map::Orientation)
765 Q_DECLARE_METATYPE(Tiled::Map::LayerDataFormat)
766 Q_DECLARE_METATYPE(Tiled::Map::RenderOrder)
767