diff options
| -rw-r--r-- | tools/sprite_dumper/identifier.h | 26 | ||||
| -rw-r--r-- | tools/sprite_dumper/tileset_dumper.cpp | 402 |
2 files changed, 250 insertions, 178 deletions
| diff --git a/tools/sprite_dumper/identifier.h b/tools/sprite_dumper/identifier.h index 74d83ce..4aac943 100644 --- a/tools/sprite_dumper/identifier.h +++ b/tools/sprite_dumper/identifier.h | |||
| @@ -5,6 +5,15 @@ | |||
| 5 | #include <vector> | 5 | #include <vector> |
| 6 | 6 | ||
| 7 | template <typename T> | 7 | template <typename T> |
| 8 | class DefaultKeyExtract { | ||
| 9 | public: | ||
| 10 | |||
| 11 | const T& operator()(const T& val) const { | ||
| 12 | return val; | ||
| 13 | } | ||
| 14 | }; | ||
| 15 | |||
| 16 | template <typename T, typename KeyExtract = DefaultKeyExtract<T>> | ||
| 8 | class identifier { | 17 | class identifier { |
| 9 | public: | 18 | public: |
| 10 | 19 | ||
| @@ -12,20 +21,21 @@ public: | |||
| 12 | 21 | ||
| 13 | private: | 22 | private: |
| 14 | 23 | ||
| 24 | using key_type = std::remove_reference_t<std::invoke_result_t<KeyExtract, const T&>>; | ||
| 15 | using vector_type = std::vector<value_type>; | 25 | using vector_type = std::vector<value_type>; |
| 16 | 26 | ||
| 17 | public: | 27 | public: |
| 18 | 28 | ||
| 19 | using key_type = typename vector_type::size_type; | 29 | using id_type = typename vector_type::size_type; |
| 20 | 30 | ||
| 21 | key_type add(const value_type& val) | 31 | id_type add(const value_type& val) |
| 22 | { | 32 | { |
| 23 | auto it = ids_.find(val); | 33 | auto it = ids_.find(KeyExtract()(val)); |
| 24 | 34 | ||
| 25 | if (it == std::end(ids_)) | 35 | if (it == std::end(ids_)) |
| 26 | { | 36 | { |
| 27 | key_type ret = ids_.size(); | 37 | id_type ret = ids_.size(); |
| 28 | ids_[val] = ret; | 38 | ids_[KeyExtract()(val)] = ret; |
| 29 | 39 | ||
| 30 | uniq_.push_back(val); | 40 | uniq_.push_back(val); |
| 31 | 41 | ||
| @@ -40,19 +50,19 @@ public: | |||
| 40 | ids_.clear(); | 50 | ids_.clear(); |
| 41 | } | 51 | } |
| 42 | 52 | ||
| 43 | inline const value_type& get(key_type i) const | 53 | inline const value_type& get(id_type i) const |
| 44 | { | 54 | { |
| 45 | return uniq_.at(i); | 55 | return uniq_.at(i); |
| 46 | } | 56 | } |
| 47 | 57 | ||
| 48 | inline key_type size() const | 58 | inline id_type size() const |
| 49 | { | 59 | { |
| 50 | return uniq_.size(); | 60 | return uniq_.size(); |
| 51 | } | 61 | } |
| 52 | 62 | ||
| 53 | private: | 63 | private: |
| 54 | 64 | ||
| 55 | std::map<value_type, key_type> ids_; | 65 | std::map<key_type, id_type> ids_; |
| 56 | vector_type uniq_; | 66 | vector_type uniq_; |
| 57 | }; | 67 | }; |
| 58 | 68 | ||
| diff --git a/tools/sprite_dumper/tileset_dumper.cpp b/tools/sprite_dumper/tileset_dumper.cpp index f09fbd9..4ca0785 100644 --- a/tools/sprite_dumper/tileset_dumper.cpp +++ b/tools/sprite_dumper/tileset_dumper.cpp | |||
| @@ -104,111 +104,196 @@ std::vector<std::vector<char>> GetMapLayers(BufferView m3, int roomId) { | |||
| 104 | return layers; | 104 | return layers; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | using metatile_id = identifier<unsigned short>::key_type; | ||
| 108 | |||
| 109 | struct TileUse { | 107 | struct TileUse { |
| 110 | metatile_id id; | 108 | size_t id; |
| 111 | bool tflipx = false; | 109 | bool tflipx = false; |
| 112 | bool tflipy = false; | 110 | bool tflipy = false; |
| 113 | }; | 111 | }; |
| 114 | 112 | ||
| 115 | Magick::Image renderTile(unsigned short ch, bool tflipx, bool tflipy, const std::vector<Palette>& palettes, const std::vector<char>& mapTiles, const std::vector<std::vector<char>>& tilesets) { | 113 | unsigned short stripFlipInfo(unsigned short ch) { |
| 116 | Magick::Image result("16x16", "transparent"); | 114 | return ch & ~(0x4000 | 0x8000); |
| 115 | } | ||
| 117 | 116 | ||
| 118 | unsigned short tile16 = ch & 0x3FF; | 117 | class Map { |
| 119 | if ((tile16 >> 6) >= 12) return result; | 118 | public: |
| 119 | |||
| 120 | Map( | ||
| 121 | BufferView m3, | ||
| 122 | int roomNum, | ||
| 123 | RoomInfo roomInfo, | ||
| 124 | RoomGfxPal roomGfxPal) | ||
| 125 | : roomNum_(roomNum), | ||
| 126 | width_(roomInfo.width), | ||
| 127 | height_(roomInfo.height), | ||
| 128 | palettes_(roomGfxPal.GetPalettes(m3)), | ||
| 129 | tilesets_(roomGfxPal.GetTilesets(m3)), | ||
| 130 | mapTiles_(GetMapTiles(m3, roomNum)), | ||
| 131 | mapLayers_(GetMapLayers(m3, roomNum)) | ||
| 132 | { | ||
| 133 | for (int layer=0; layer<mapLayers_.size(); layer++) { | ||
| 134 | const std::vector<char>& ml = mapLayers_[layer]; | ||
| 135 | if (ml.empty()) continue; | ||
| 136 | |||
| 137 | std::vector<TileUse> newLayer; | ||
| 138 | |||
| 139 | for (int mapy = 0; mapy < height_; mapy++) { | ||
| 140 | for (int mapx = 0; mapx < width_; mapx++) { | ||
| 141 | unsigned short ch = BufferView(ml).ReadTwoBytes((mapx + (mapy * width_)) * 2); | ||
| 142 | TileUse tu; | ||
| 143 | tu.id = metatiles_.add(stripFlipInfo(ch)); | ||
| 144 | tu.tflipx = (ch & 0x4000) != 0; | ||
| 145 | tu.tflipy = (ch & 0x8000) != 0; | ||
| 146 | newLayer.push_back(std::move(tu)); | ||
| 147 | } | ||
| 148 | } | ||
| 120 | 149 | ||
| 121 | result.modifyImage(); | 150 | itemised_.push_back(std::move(newLayer)); |
| 122 | Magick::Pixels view(result); | 151 | } |
| 123 | 152 | ||
| 124 | int tpal = (ch >> 10) & 0xF; | 153 | // Debug info |
| 125 | const Palette& palette = palettes[tpal]; | 154 | std::cout << width_ << "," << height_ << std::endl; |
| 155 | std::cout << roomGfxPal.paletteId; | ||
| 156 | for (int i=0;i<12;i++) std::cout << "," << roomGfxPal.tilesetId[i]; | ||
| 157 | std::cout << std::endl; | ||
| 158 | } | ||
| 126 | 159 | ||
| 127 | // bool tflipx = tu.tflipx;//(ch & 0x4000) != 0; | 160 | Magick::Image renderTile(size_t metatile_id, bool tflipx, bool tflipy) const { |
| 128 | // bool tflipy = tu.tflipy;//(ch & 0x8000) != 0; | 161 | Magick::Image result("16x16", "transparent"); |
| 129 | 162 | ||
| 130 | int tile8[2][2]; | 163 | unsigned short ch = metatiles_.get(metatile_id); |
| 131 | bool sflipx[2][2]; | 164 | unsigned short tile16 = ch & 0x3FF; |
| 132 | bool sflipy[2][2]; | 165 | if ((tile16 >> 6) >= 12) return result; |
| 133 | 166 | ||
| 134 | unsigned int magic = BufferView(mapTiles).ReadFourBytes(tile16 * 8); | 167 | result.modifyImage(); |
| 168 | Magick::Pixels view(result); | ||
| 135 | 169 | ||
| 136 | tile8[0][0] = mapTiles[(tile16 * 8) + 4]; | 170 | int tpal = (ch >> 10) & 0xF; |
| 137 | tile8[0][1] = mapTiles[(tile16 * 8) + 5]; | 171 | const Palette& palette = palettes_[tpal]; |
| 138 | tile8[1][0] = mapTiles[(tile16 * 8) + 6]; | ||
| 139 | tile8[1][1] = mapTiles[(tile16 * 8) + 7]; | ||
| 140 | 172 | ||
| 141 | for (int i=0; i<2; i++) { | 173 | int tile8[2][2]; |
| 142 | for (int j=0; j<2; j++) { | 174 | bool sflipx[2][2]; |
| 143 | sflipx[i][j] = (tile8[i][j] & 0x40) != 0; | 175 | bool sflipy[2][2]; |
| 144 | sflipy[i][j] = (tile8[i][j] & 0x80) != 0; | ||
| 145 | 176 | ||
| 146 | tile8[i][j] &= 0x3f; | 177 | unsigned int magic = BufferView(mapTiles_).ReadFourBytes(tile16 * 8); |
| 147 | tile8[i][j] |= (ch & 0x3c0); | 178 | |
| 179 | tile8[0][0] = mapTiles_[(tile16 * 8) + 4]; | ||
| 180 | tile8[0][1] = mapTiles_[(tile16 * 8) + 5]; | ||
| 181 | tile8[1][0] = mapTiles_[(tile16 * 8) + 6]; | ||
| 182 | tile8[1][1] = mapTiles_[(tile16 * 8) + 7]; | ||
| 183 | |||
| 184 | for (int i=0; i<2; i++) { | ||
| 185 | for (int j=0; j<2; j++) { | ||
| 186 | sflipx[i][j] = (tile8[i][j] & 0x40) != 0; | ||
| 187 | sflipy[i][j] = (tile8[i][j] & 0x80) != 0; | ||
| 188 | |||
| 189 | tile8[i][j] &= 0x3f; | ||
| 190 | tile8[i][j] |= (ch & 0x3c0); | ||
| 191 | } | ||
| 148 | } | 192 | } |
| 149 | } | ||
| 150 | 193 | ||
| 151 | unsigned int mask = (magic >> 16) & 0xf; | 194 | unsigned int mask = (magic >> 16) & 0xf; |
| 152 | if ((mask & 0x1) == 0) tile8[0][0] = -1; | 195 | if ((mask & 0x1) == 0) tile8[0][0] = -1; |
| 153 | if ((mask & 0x2) == 0) tile8[0][1] = -1; | 196 | if ((mask & 0x2) == 0) tile8[0][1] = -1; |
| 154 | if ((mask & 0x4) == 0) tile8[1][0] = -1; | 197 | if ((mask & 0x4) == 0) tile8[1][0] = -1; |
| 155 | if ((mask & 0x8) == 0) tile8[1][1] = -1; | 198 | if ((mask & 0x8) == 0) tile8[1][1] = -1; |
| 156 | 199 | ||
| 157 | for (int tiley=0; tiley<2; tiley++) { | 200 | for (int tiley=0; tiley<2; tiley++) { |
| 158 | for (int tilex=0; tilex<2; tilex++) { | 201 | for (int tilex=0; tilex<2; tilex++) { |
| 159 | if (tile8[tiley][tilex] < 0) continue; | 202 | if (tile8[tiley][tilex] < 0) continue; |
| 160 | 203 | ||
| 161 | int tileset = tile8[tiley][tilex] >> 6; | 204 | int tileset = tile8[tiley][tilex] >> 6; |
| 162 | int subtile = tile8[tiley][tilex] & 0x3f; | 205 | int subtile = tile8[tiley][tilex] & 0x3f; |
| 163 | 206 | ||
| 164 | int tileData[8][8]; | 207 | int tileData[8][8]; |
| 165 | BufferView tilesetData(tilesets[tileset]); | 208 | BufferView tilesetData(tilesets_[tileset]); |
| 166 | tilesetData.Seek(subtile << 5); | 209 | tilesetData.Seek(subtile << 5); |
| 167 | for (int ty=0; ty<8; ty++) { | 210 | for (int ty=0; ty<8; ty++) { |
| 168 | for (int tx=0; tx<4; tx++) { | 211 | for (int tx=0; tx<4; tx++) { |
| 169 | unsigned char vvvv = tilesetData.ReadNextByte(); | 212 | unsigned char vvvv = tilesetData.ReadNextByte(); |
| 170 | tileData[tx*2][ty] = static_cast<unsigned char>(vvvv & 0xF); | 213 | tileData[tx*2][ty] = static_cast<unsigned char>(vvvv & 0xF); |
| 171 | tileData[tx*2+1][ty] = static_cast<unsigned char>((vvvv >> 4) & 0xF); | 214 | tileData[tx*2+1][ty] = static_cast<unsigned char>((vvvv >> 4) & 0xF); |
| 215 | } | ||
| 172 | } | 216 | } |
| 173 | } | ||
| 174 | 217 | ||
| 175 | int stx = tflipx ? 1 - tilex : tilex; | 218 | int stx = tflipx ? 1 - tilex : tilex; |
| 176 | int sty = tflipy ? 1 - tiley : tiley; | 219 | int sty = tflipy ? 1 - tiley : tiley; |
| 177 | 220 | ||
| 178 | int destX = /*(mapx << 4) +*/ (stx << 3); | 221 | int destX = /*(mapx << 4) +*/ (stx << 3); |
| 179 | int destY = /*(mapy << 4) +*/ (sty << 3); | 222 | int destY = /*(mapy << 4) +*/ (sty << 3); |
| 180 | 223 | ||
| 181 | bool reallyFlipX = (sflipx[tiley][tilex] ^ tflipx); | 224 | bool reallyFlipX = (sflipx[tiley][tilex] ^ tflipx); |
| 182 | bool reallyFlipY = (sflipy[tiley][tilex] ^ tflipy); | 225 | bool reallyFlipY = (sflipy[tiley][tilex] ^ tflipy); |
| 183 | 226 | ||
| 184 | Magick::PixelPacket* pixels = view.get(destX,destY,8,8); | 227 | Magick::PixelPacket* pixels = view.get(destX,destY,8,8); |
| 185 | 228 | ||
| 186 | for (int ty=0; ty<8; ty++) { | 229 | for (int ty=0; ty<8; ty++) { |
| 187 | int actualTy = reallyFlipY ? (7-ty) : ty; | 230 | int actualTy = reallyFlipY ? (7-ty) : ty; |
| 188 | 231 | ||
| 189 | for (int tx=0; tx<8; tx++) { | 232 | for (int tx=0; tx<8; tx++) { |
| 190 | int actualTx = reallyFlipX ? (7-tx) : tx; | 233 | int actualTx = reallyFlipX ? (7-tx) : tx; |
| 191 | 234 | ||
| 192 | if (tileData[actualTx][actualTy] != 0) { | 235 | if (tileData[actualTx][actualTy] != 0) { |
| 193 | //auto& c = palette.Colors().at(tileData[actualTx][actualTy]); | 236 | //auto& c = palette.Colors().at(tileData[actualTx][actualTy]); |
| 194 | //std::cout << c.redQuantum() << "," << c.greenQuantum() << "," << c.blueQuantum() << std::endl; | 237 | //std::cout << c.redQuantum() << "," << c.greenQuantum() << "," << c.blueQuantum() << std::endl; |
| 195 | *pixels = palette.Colors().at(tileData[actualTx][actualTy]); | 238 | *pixels = palette.Colors().at(tileData[actualTx][actualTy]); |
| 196 | //std::cout << tileData[actualTx][actualTy] << std::endl; | 239 | //std::cout << tileData[actualTx][actualTy] << std::endl; |
| 240 | } | ||
| 241 | pixels++; | ||
| 197 | } | 242 | } |
| 198 | pixels++; | ||
| 199 | } | 243 | } |
| 200 | } | ||
| 201 | 244 | ||
| 202 | view.sync(); | 245 | view.sync(); |
| 246 | } | ||
| 203 | } | 247 | } |
| 248 | |||
| 249 | return result; | ||
| 204 | } | 250 | } |
| 205 | 251 | ||
| 206 | return result; | 252 | const std::vector<std::vector<TileUse>>& getItemisedLayers() const { |
| 207 | } | 253 | return itemised_; |
| 254 | } | ||
| 208 | 255 | ||
| 209 | unsigned short stripFlipInfo(unsigned short ch) { | 256 | int getWidth() const { return width_; } |
| 210 | return ch & ~(0x4000 | 0x8000); | 257 | |
| 211 | } | 258 | int getHeight() const { return height_; } |
| 259 | |||
| 260 | int getRoomNum() const { return roomNum_; } | ||
| 261 | |||
| 262 | private: | ||
| 263 | |||
| 264 | int roomNum_; | ||
| 265 | int width_; | ||
| 266 | int height_; | ||
| 267 | std::vector<Palette> palettes_; | ||
| 268 | std::vector<std::vector<char>> tilesets_; | ||
| 269 | std::vector<char> mapTiles_; | ||
| 270 | std::vector<std::vector<char>> mapLayers_; | ||
| 271 | |||
| 272 | identifier<unsigned short> metatiles_; | ||
| 273 | std::vector<std::vector<TileUse>> itemised_; | ||
| 274 | }; | ||
| 275 | |||
| 276 | struct GlobalTile { | ||
| 277 | Magick::Image image; | ||
| 278 | std::string base64; | ||
| 279 | |||
| 280 | GlobalTile(Magick::Image input) : image(input) { | ||
| 281 | Magick::Blob blob; | ||
| 282 | input.write(&blob); | ||
| 283 | base64 = blob.base64(); | ||
| 284 | } | ||
| 285 | }; | ||
| 286 | |||
| 287 | class GlobalTileKeyExtract { | ||
| 288 | public: | ||
| 289 | |||
| 290 | const std::string& operator()(const GlobalTile& globaltile) const { | ||
| 291 | return globaltile.base64; | ||
| 292 | } | ||
| 293 | }; | ||
| 294 | |||
| 295 | using globaltile_identifier = identifier<GlobalTile, GlobalTileKeyExtract>; | ||
| 296 | using globaltile_id = globaltile_identifier::id_type; | ||
| 212 | 297 | ||
| 213 | int main(int argc, char** argv) { | 298 | int main(int argc, char** argv) { |
| 214 | if (argc < 3) { | 299 | if (argc < 3) { |
| @@ -222,125 +307,102 @@ int main(int argc, char** argv) { | |||
| 222 | auto roomInfos = RoomInfo::ReadFromRom(m3.buffer()); | 307 | auto roomInfos = RoomInfo::ReadFromRom(m3.buffer()); |
| 223 | auto roomGfxPals = RoomGfxPal::ReadFromRom(m3.buffer()); | 308 | auto roomGfxPals = RoomGfxPal::ReadFromRom(m3.buffer()); |
| 224 | 309 | ||
| 225 | int roomNum = std::stoi(argv[2]); | 310 | std::list<Map> maps; |
| 226 | 311 | for (int i=2; i<argc; i++) { | |
| 227 | std::cout << roomInfos[roomNum].width << "," << roomInfos[roomNum].height << std::endl; | 312 | int roomNum = std::stoi(argv[i]); |
| 228 | std::cout << roomGfxPals[roomNum].paletteId; | 313 | maps.emplace_back(m3.buffer(), roomNum, roomInfos[roomNum], roomGfxPals[roomNum]); |
| 229 | for (int i=0;i<12;i++) std::cout << "," << roomGfxPals[roomNum].tilesetId[i]; | 314 | } |
| 230 | std::cout << std::endl; | ||
| 231 | 315 | ||
| 232 | int width = roomInfos[roomNum].width; | 316 | globaltile_identifier globaltiles; |
| 233 | int height = roomInfos[roomNum].height; | 317 | for (const Map& map : maps) { |
| 318 | std::map<int, int> translatedTileIds; | ||
| 234 | 319 | ||
| 235 | Magick::Image image(Magick::Geometry(width*16, height*16), "transparent"); | 320 | // Generate map datafile. |
| 321 | std::ofstream mapfile("out" + std::to_string(map.getRoomNum()) + ".tmx"); | ||
| 322 | mapfile << R"(<map version="1.0" orientation="orthogonal" renderorder="right-down" width=")"; | ||
| 323 | mapfile << map.getWidth(); | ||
| 324 | mapfile << R"(" height=")"; | ||
| 325 | mapfile << map.getHeight(); | ||
| 326 | mapfile << R"(" tilewidth="16" tileheight="16">)" << std::endl; | ||
| 327 | mapfile << R"( <tileset firstgid="1" source="out.tsx" />)" << std::endl; | ||
| 328 | |||
| 329 | for (int layer = map.getItemisedLayers().size()-1; layer >= 0; layer--) { | ||
| 330 | mapfile << R"( <layer id=")"; | ||
| 331 | mapfile << layer; | ||
| 332 | mapfile << R"(" name="Layer )"; | ||
| 333 | mapfile << layer; | ||
| 334 | mapfile << R"(" width=")"; | ||
| 335 | mapfile << map.getWidth(); | ||
| 336 | mapfile << R"(" height=")"; | ||
| 337 | mapfile << map.getHeight(); | ||
| 338 | mapfile << R"(">)" << std::endl; | ||
| 339 | mapfile << R"( <data encoding="csv">)"; | ||
| 340 | |||
| 341 | bool first = true; | ||
| 342 | for (const TileUse& tu : map.getItemisedLayers()[layer]) { | ||
| 343 | if (first) { | ||
| 344 | first = false; | ||
| 345 | } else { | ||
| 346 | mapfile << ","; | ||
| 347 | } | ||
| 236 | 348 | ||
| 237 | auto mapTiles = GetMapTiles(m3.buffer(), roomNum); | 349 | if (!translatedTileIds.count(tu.id)) { |
| 238 | auto mapLayers = GetMapLayers(m3.buffer(), roomNum); | 350 | Magick::Image renderedTile = map.renderTile(tu.id, false, false); |
| 351 | renderedTile.magick("png"); | ||
| 239 | 352 | ||
| 240 | const auto& gfxPal = roomGfxPals[roomNum]; | 353 | GlobalTile gt(std::move(renderedTile)); |
| 241 | auto palettes = gfxPal.GetPalettes(m3.buffer()); | 354 | translatedTileIds[tu.id] = globaltiles.add(gt); |
| 242 | auto tilesets = gfxPal.GetTilesets(m3.buffer()); | 355 | } |
| 243 | 356 | ||
| 244 | identifier<unsigned short> metatiles; | 357 | unsigned int outChar = translatedTileIds[tu.id] + 1; |
| 245 | std::vector<std::vector<TileUse>> itemised; | 358 | if (tu.tflipx) outChar |= 0x80000000; |
| 359 | if (tu.tflipy) outChar |= 0x40000000; | ||
| 360 | mapfile << outChar; | ||
| 361 | } | ||
| 246 | 362 | ||
| 247 | for (int layer=0; layer<mapLayers.size(); layer++) { | 363 | mapfile << R"(</data>)" << std::endl; |
| 248 | const std::vector<char>& ml = mapLayers[layer]; | 364 | mapfile << R"( </layer>)" << std::endl; |
| 249 | if (ml.empty()) continue; | 365 | } |
| 250 | 366 | ||
| 251 | std::vector<TileUse> newLayer; | 367 | mapfile << R"(</map>)" << std::endl; |
| 252 | 368 | ||
| 253 | for (int mapy = 0; mapy < height; mapy++) { | 369 | // Render map to image. |
| 254 | for (int mapx = 0; mapx < width; mapx++) { | 370 | /*for (int layer=itemised.size()-1; layer>=0; layer--) { |
| 255 | unsigned short ch = BufferView(ml).ReadTwoBytes((mapx + (mapy * width)) * 2); | 371 | for (int mapy = 0; mapy < height; mapy++) { |
| 256 | TileUse tu; | 372 | for (int mapx = 0; mapx < width; mapx++) { |
| 257 | tu.id = metatiles.add(stripFlipInfo(ch)); | 373 | const TileUse& tu = itemised[layer][mapx+mapy*width]; |
| 258 | tu.tflipx = (ch & 0x4000) != 0; | 374 | Magick::Image tileRender = renderTile(metatiles.get(tu.id), tu.tflipx, tu.tflipy, palettes, mapTiles, tilesets); |
| 259 | tu.tflipy = (ch & 0x8000) != 0; | 375 | image.composite(tileRender, mapx << 4, mapy << 4, Magick::OverCompositeOp); |
| 260 | newLayer.push_back(std::move(tu)); | 376 | } |
| 261 | } | 377 | } |
| 262 | } | 378 | }*/ |
| 263 | |||
| 264 | itemised.push_back(std::move(newLayer)); | ||
| 265 | } | 379 | } |
| 266 | 380 | ||
| 267 | constexpr int TILES_PER_ROW = 10; | 381 | constexpr int TILES_PER_ROW = 10; |
| 268 | int sheetWidth; | 382 | int sheetWidth; |
| 269 | int sheetHeight; | 383 | int sheetHeight; |
| 270 | 384 | ||
| 271 | if (metatiles.size() < TILES_PER_ROW) { | 385 | if (globaltiles.size() < TILES_PER_ROW) { |
| 272 | sheetWidth = metatiles.size() * 16; | 386 | sheetWidth = globaltiles.size() * 16; |
| 273 | sheetHeight = 16; | 387 | sheetHeight = 16; |
| 274 | } else { | 388 | } else { |
| 275 | sheetWidth = TILES_PER_ROW * 16; | 389 | sheetWidth = TILES_PER_ROW * 16; |
| 276 | sheetHeight = (metatiles.size() / TILES_PER_ROW + 1) * 16; | 390 | sheetHeight = (globaltiles.size() / TILES_PER_ROW + 1) * 16; |
| 277 | } | ||
| 278 | |||
| 279 | // Generate map datafile. | ||
| 280 | std::ofstream mapfile("out.tmx"); | ||
| 281 | mapfile << R"(<map version="1.0" orientation="orthogonal" renderorder="right-down" width=")"; | ||
| 282 | mapfile << width; | ||
| 283 | mapfile << R"(" height=")"; | ||
| 284 | mapfile << height; | ||
| 285 | mapfile << R"(" tilewidth="16" tileheight="16">)" << std::endl; | ||
| 286 | mapfile << R"( <tileset firstgid="1" name="fromRom" tilewidth="16" tileheight="16" tilecount=")"; | ||
| 287 | mapfile << metatiles.size(); | ||
| 288 | mapfile << R"(" columns=")"; | ||
| 289 | mapfile << TILES_PER_ROW; | ||
| 290 | mapfile << R"(">)" << std::endl; | ||
| 291 | mapfile << R"( <image source="tiles.png" />)" << std::endl; | ||
| 292 | mapfile << R"( </tileset>)" << std::endl; | ||
| 293 | |||
| 294 | for (int layer=itemised.size()-1; layer>=0; layer--) { | ||
| 295 | mapfile << R"( <layer id=")"; | ||
| 296 | mapfile << layer; | ||
| 297 | mapfile << R"(" name="Layer )"; | ||
| 298 | mapfile << layer; | ||
| 299 | mapfile << R"(" width=")"; | ||
| 300 | mapfile << width; | ||
| 301 | mapfile << R"(" height=")"; | ||
| 302 | mapfile << height; | ||
| 303 | mapfile << R"(">)" << std::endl; | ||
| 304 | mapfile << R"( <data encoding="csv">)"; | ||
| 305 | |||
| 306 | bool first = true; | ||
| 307 | for (const TileUse& tu : itemised[layer]) { | ||
| 308 | if (first) { | ||
| 309 | first = false; | ||
| 310 | } else { | ||
| 311 | mapfile << ","; | ||
| 312 | } | ||
| 313 | |||
| 314 | unsigned int outChar = tu.id + 1; | ||
| 315 | if (tu.tflipx) outChar |= 0x80000000; | ||
| 316 | if (tu.tflipy) outChar |= 0x40000000; | ||
| 317 | mapfile << outChar; | ||
| 318 | } | ||
| 319 | |||
| 320 | mapfile << R"(</data>)" << std::endl; | ||
| 321 | mapfile << R"( </layer>)" << std::endl; | ||
| 322 | } | ||
| 323 | |||
| 324 | mapfile << R"(</map>)" << std::endl; | ||
| 325 | |||
| 326 | // Render map to image. | ||
| 327 | for (int layer=itemised.size()-1; layer>=0; layer--) { | ||
| 328 | for (int mapy = 0; mapy < height; mapy++) { | ||
| 329 | for (int mapx = 0; mapx < width; mapx++) { | ||
| 330 | const TileUse& tu = itemised[layer][mapx+mapy*width]; | ||
| 331 | Magick::Image tileRender = renderTile(metatiles.get(tu.id), tu.tflipx, tu.tflipy, palettes, mapTiles, tilesets); | ||
| 332 | image.composite(tileRender, mapx << 4, mapy << 4, Magick::OverCompositeOp); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | 391 | } |
| 336 | 392 | ||
| 337 | image.magick("png"); | 393 | std::ofstream tilesetfile("out.tsx"); |
| 338 | image.write("out.png"); | 394 | tilesetfile << R"(<tileset name="fromRom" tilewidth="16" tileheight="16" tilecount=")"; |
| 395 | tilesetfile << globaltiles.size(); | ||
| 396 | tilesetfile << R"(" columns=")"; | ||
| 397 | tilesetfile << TILES_PER_ROW; | ||
| 398 | tilesetfile << R"(">)" << std::endl; | ||
| 399 | tilesetfile << R"( <image source="tiles.png" />)" << std::endl; | ||
| 400 | tilesetfile << R"(</tileset>)" << std::endl; | ||
| 339 | 401 | ||
| 340 | // Render tileset image. | 402 | // Render tileset image. |
| 341 | Magick::Image tilesetImage(Magick::Geometry(sheetWidth, sheetHeight), "transparent"); | 403 | Magick::Image tilesetImage(Magick::Geometry(sheetWidth, sheetHeight), "transparent"); |
| 342 | for (int i=0; i<metatiles.size(); i++) { | 404 | for (int i=0; i<globaltiles.size(); i++) { |
| 343 | Magick::Image tileRender = renderTile(metatiles.get(i), false, false, palettes, mapTiles, tilesets); | 405 | const Magick::Image& tileRender = globaltiles.get(i).image; |
| 344 | tilesetImage.composite(tileRender, (i % TILES_PER_ROW) << 4, (i / TILES_PER_ROW) << 4, Magick::OverCompositeOp); | 406 | tilesetImage.composite(tileRender, (i % TILES_PER_ROW) << 4, (i / TILES_PER_ROW) << 4, Magick::OverCompositeOp); |
| 345 | } | 407 | } |
| 346 | 408 | ||
