| 1 | // Aseprite Document Library |
| 2 | // Copyright (c) 2019-2021 Igara Studio S.A. |
| 3 | // |
| 4 | // This file is released under the terms of the MIT license. |
| 5 | // Read LICENSE.txt for more information. |
| 6 | |
| 7 | #ifndef DOC_TILESET_H_INCLUDED |
| 8 | #define DOC_TILESET_H_INCLUDED |
| 9 | #pragma once |
| 10 | |
| 11 | #include "doc/grid.h" |
| 12 | #include "doc/image_ref.h" |
| 13 | #include "doc/object.h" |
| 14 | #include "doc/tile.h" |
| 15 | #include "doc/tileset_hash_table.h" |
| 16 | |
| 17 | #include <string> |
| 18 | #include <vector> |
| 19 | |
| 20 | namespace doc { |
| 21 | |
| 22 | class Remap; |
| 23 | class Sprite; |
| 24 | |
| 25 | class Tileset : public Object { |
| 26 | public: |
| 27 | typedef std::vector<ImageRef> Tiles; |
| 28 | typedef Tiles::iterator iterator; |
| 29 | typedef Tiles::const_iterator const_iterator; |
| 30 | |
| 31 | // Creates a new tileset with "ntiles". The first tile will be |
| 32 | // always the empty tile. So ntiles must be > 1 to contain at |
| 33 | // least one non-empty tile. |
| 34 | Tileset(Sprite* sprite, |
| 35 | const Grid& grid, |
| 36 | const tileset_index ntiles); |
| 37 | |
| 38 | static Tileset* MakeCopyWithSameImages(const Tileset* tileset); |
| 39 | static Tileset* MakeCopyCopyingImages(const Tileset* tileset); |
| 40 | |
| 41 | Sprite* sprite() const { return m_sprite; } |
| 42 | const Grid& grid() const { return m_grid; } |
| 43 | |
| 44 | const std::string& name() const { return m_name; } |
| 45 | void setName(const std::string& name) { m_name = name; } |
| 46 | |
| 47 | int baseIndex() const { return m_baseIndex; } |
| 48 | void setBaseIndex(int index) { m_baseIndex = index; } |
| 49 | |
| 50 | int getMemSize() const override; |
| 51 | |
| 52 | iterator begin() { return m_tiles.begin(); } |
| 53 | iterator end() { return m_tiles.end(); } |
| 54 | const_iterator begin() const { return m_tiles.begin(); } |
| 55 | const_iterator end() const { return m_tiles.end(); } |
| 56 | tile_index size() const { return tile_index(m_tiles.size()); } |
| 57 | void resize(const tile_index ntiles); |
| 58 | void remap(const Remap& remap); |
| 59 | |
| 60 | ImageRef get(const tile_index ti) const { |
| 61 | if (ti >= 0 && ti < size()) |
| 62 | return m_tiles[ti]; |
| 63 | else |
| 64 | return ImageRef(nullptr); |
| 65 | } |
| 66 | void set(const tile_index ti, |
| 67 | const ImageRef& image); |
| 68 | |
| 69 | tile_index add(const ImageRef& image); |
| 70 | void insert(const tile_index ti, |
| 71 | const ImageRef& image); |
| 72 | void erase(const tile_index ti); |
| 73 | |
| 74 | // Linked with an external file |
| 75 | void setExternal(const std::string& filename, |
| 76 | const tileset_index& tsi); |
| 77 | const std::string& externalFilename() const { return m_external.filename; } |
| 78 | tileset_index externalTileset() const { return m_external.tileset; } |
| 79 | |
| 80 | bool operator==(const Tileset& other) const { |
| 81 | // TODO compare the all grid members |
| 82 | return (m_grid.tileSize() == other.m_grid.tileSize() && |
| 83 | m_tiles == other.m_tiles && |
| 84 | m_name == other.m_name); |
| 85 | } |
| 86 | |
| 87 | bool operator!=(const Tileset& other) const { |
| 88 | return !operator==(other); |
| 89 | } |
| 90 | |
| 91 | // Returns a new empty tile with the tileset specs. |
| 92 | ImageRef makeEmptyTile(); |
| 93 | |
| 94 | // If there is a tile in the set that matches the pixels of the |
| 95 | // given "tileImage", this function returns true and the index of |
| 96 | // that tile in the "ti" parameter. Returns false if the image is |
| 97 | // not in the tileset. |
| 98 | // |
| 99 | // Warning: Use preprocess_transparent_pixels() with tileImage |
| 100 | // before calling this function. |
| 101 | bool findTileIndex(const ImageRef& tileImage, |
| 102 | tile_index& ti); |
| 103 | |
| 104 | // Must be called when a tile image was modified externally, so |
| 105 | // the hash elements are re-calculated for that specific tile. |
| 106 | void notifyTileContentChange(const tile_index ti); |
| 107 | |
| 108 | // Called when the mask color of the sprite is modified, so we |
| 109 | // have to regenerate the empty tile with that new mask color. |
| 110 | void notifyRegenerateEmptyTile(); |
| 111 | |
| 112 | #ifdef _DEBUG |
| 113 | void assertValidHashTable(); |
| 114 | #endif |
| 115 | |
| 116 | private: |
| 117 | void removeFromHash(const tile_index ti, |
| 118 | const bool adjustIndexes); |
| 119 | void hashImage(const tile_index ti, |
| 120 | const ImageRef& tileImage); |
| 121 | void rehash(); |
| 122 | TilesetHashTable& hashTable(); |
| 123 | |
| 124 | Sprite* m_sprite; |
| 125 | Grid m_grid; |
| 126 | Tiles m_tiles; |
| 127 | TilesetHashTable m_hash; |
| 128 | std::string m_name; |
| 129 | int m_baseIndex = 1; |
| 130 | struct External { |
| 131 | std::string filename; |
| 132 | tileset_index tileset; |
| 133 | } m_external; |
| 134 | }; |
| 135 | |
| 136 | } // namespace doc |
| 137 | |
| 138 | #endif |
| 139 | |