From 7b35a18c93511482b644e6a0ed1dbd9de11eff07 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 31 Jan 2021 22:33:48 -0500 Subject: Progress on map dumper, now renders images with holes in them --- tools/sprite_dumper/tileset_dumper.cpp | 217 +++++++++++++++++++++++++++++---- 1 file changed, 194 insertions(+), 23 deletions(-) (limited to 'tools/sprite_dumper/tileset_dumper.cpp') diff --git a/tools/sprite_dumper/tileset_dumper.cpp b/tools/sprite_dumper/tileset_dumper.cpp index c0cea76..de6e1f4 100644 --- a/tools/sprite_dumper/tileset_dumper.cpp +++ b/tools/sprite_dumper/tileset_dumper.cpp @@ -5,7 +5,8 @@ #include #include "common.h" -const int NUM_ROOMS = 1000; +constexpr int NUM_ROOMS = 1000; +constexpr int NUM_TILESETS = 12; struct RoomInfo { int width; @@ -28,6 +29,79 @@ struct RoomInfo { } }; +struct RoomGfxPal { + int paletteId; + int tilesetId[NUM_TILESETS]; + + static std::map ReadFromRom(BufferView m3) { + const int BASE_ADDR = 0xD34F44 + 12; + const int ENTRY_LEN = 26; + + std::map output; + + for (int i=0; i(m3.ReadTwoBytes(BASE_ADDR + i*ENTRY_LEN + 24)); + for (int tid=0; tid> GetTilesets(BufferView m3) const { + const int BASE_ADDR = 0xD3B4E0; + + std::vector> output(NUM_TILESETS); + + for (int i=0; i GetPalettes(BufferView m3) const { + const int BASE_ADDR = 0xF3C344; + + std::vector output; + int offset = m3.ReadFourBytes(BASE_ADDR + 4 + (paletteId << 2)); + + for (int i=0; i<16; i++) { + unsigned long palAddr = BASE_ADDR + offset + (i << 5); + output.emplace_back(m3, palAddr); + } + + return output; + } +}; + +std::vector GetMapTiles(BufferView m3, int roomId) { + const int BASE_ADDR = 0x104D9CC; + int tilesAddr = m3.ReadFourBytes(BASE_ADDR + 4 + (roomId << 2)) + BASE_ADDR; + return m3.Decompress(tilesAddr); +} + +std::vector> GetMapLayers(BufferView m3, int roomId) { + const int BASE_ADDR = 0xF9003C; + std::vector> layers; + for (int i=0; i<3; i++) { + try { + int lookAddr = BASE_ADDR + 4 + (((roomId * 3) + i) << 2); + int layerAddr = m3.ReadFourBytes(lookAddr) + BASE_ADDR; + layers.push_back(m3.Decompress(layerAddr)); + } catch (const std::domain_error&) { + // ignore + } + } + return layers; +} + int main(int argc, char** argv) { if (argc < 3) { std::cout << "Usage: ./tileset_dumper [path to rom] {map ID}" << std::endl; @@ -37,29 +111,126 @@ int main(int argc, char** argv) { Magick::InitializeMagick(nullptr); Rom m3(argv[1]); + auto roomInfos = RoomInfo::ReadFromRom(m3.buffer()); + auto roomGfxPals = RoomGfxPal::ReadFromRom(m3.buffer()); int roomNum = std::stoi(argv[2]); - auto roomInfos = RoomInfo::ReadFromRom(m3.buffer()); + std::cout << roomInfos[roomNum].width << "," << roomInfos[roomNum].height << std::endl; - /*const unsigned long ROOM_TILES_BASE = 0x104D9CC; - unsigned long metatilesInfoAddr = ROOM_TILES_BASE + 4 + (roomNum << 2); - unsigned long metatilesOffset = m3.buffer().ReadFourBytes(metatilesInfoAddr); - unsigned long metatilesAddr = metatilesOffset + ROOM_TILES_BASE; - std::vector metatiles = m3.buffer().Decompress(metatilesAddr); - std::cout << (metatiles.size()/8) << std::endl; - - for (int i=0; i<10; i++) { - int tile00 = metatiles[i*8+4]; - int tile01 = metatiles[i*8+5]; - int tile10 = metatiles[i*8+6]; - int tile11 = metatiles[i*8+7]; - - int mask = metatiles[i*8+2]; - if ((mask & 0x1) == 0) tile00 = -1; - if ((mask & 0x2) == 0) tile01 = -1; - if ((mask & 0x4) == 0) tile10 = -1; - if ((mask & 0x8) == 0) tile11 = -1; - - std::cout << tile00 << "," << tile01 << "," << tile10 << "," << tile11 << std::endl; - }*/ + std::cout << roomGfxPals[roomNum].paletteId; + for (int i=0;i<12;i++) std::cout << "," << roomGfxPals[roomNum].tilesetId[i]; + std::cout << std::endl; + + int width = roomInfos[roomNum].width; + int height = roomInfos[roomNum].height; + + Magick::Image image(Magick::Geometry(width*16, height*16), "transparent"); + image.modifyImage(); + Magick::Pixels view(image); + + auto mapTiles = GetMapTiles(m3.buffer(), roomNum); + auto mapLayers = GetMapLayers(m3.buffer(), roomNum); + + const auto& gfxPal = roomGfxPals[roomNum]; + auto palettes = gfxPal.GetPalettes(m3.buffer()); + auto tilesets = gfxPal.GetTilesets(m3.buffer()); + + for (int layer=mapLayers.size()-1; layer>=0; layer--) { + const std::vector& ml = mapLayers[layer]; + if (ml.empty()) continue; + + for (int mapy = 0; mapy < height; mapy++) { + for (int mapx = 0; mapx < width; mapx++) { + unsigned short ch = BufferView(ml).ReadTwoBytes((mapx + (mapy * width)) * 2); + unsigned short tile16 = ch & 0x3FF; + + if ((tile16 >> 6) >= 12) continue; + + int tpal = (ch >> 10) & 0xF; + const Palette& palette = palettes[tpal]; + + bool tflipx = (ch & 0x4000) != 0; + bool tflipy = (ch & 0x8000) != 0; + + int tile8[2][2]; + bool sflipx[2][2]; + bool sflipy[2][2]; + + unsigned int magic = BufferView(mapTiles).ReadFourBytes(tile16 * 8); + + tile8[0][0] = mapTiles[(tile16 * 8) + 4]; + tile8[0][1] = mapTiles[(tile16 * 8) + 5]; + tile8[1][0] = mapTiles[(tile16 * 8) + 6]; + tile8[1][1] = mapTiles[(tile16 * 8) + 7]; + + for (int i=0; i<2; i++) { + for (int j=0; j<2; j++) { + sflipx[i][j] = (tile8[i][j] & 0x40) != 0; + sflipy[i][j] = (tile8[i][j] & 0x80) != 0; + + tile8[i][j] &= 0x3f; + tile8[i][j] |= (ch & 0x3c0); + } + } + + unsigned int mask = (magic >> 16) & 0xf; + if ((mask & 0x1) == 0) tile8[0][0] = -1; + if ((mask & 0x2) == 0) tile8[0][1] = -1; + if ((mask & 0x4) == 0) tile8[1][0] = -1; + if ((mask & 0x8) == 0) tile8[1][1] = -1; + + for (int tiley=0; tiley<2; tiley++) { + for (int tilex=0; tilex<2; tilex++) { + if (tile8[tiley][tilex] < 0) continue; + + int tileset = tile8[tiley][tilex] >> 6; + int subtile = tile8[tiley][tilex] & 0x3f; + + int tileData[8][8]; + BufferView tilesetData(tilesets[tileset]); + tilesetData.Seek(subtile << 5); + for (int ty=0; ty<8; ty++) { + for (int tx=0; tx<4; tx++) { + unsigned char vvvv = tilesetData.ReadNextByte(); + tileData[tx*2][ty] = static_cast(vvvv & 0xF); + tileData[tx*2+1][ty] = static_cast((vvvv >> 4) & 0xF); + } + } + + int stx = tflipx ? 1 - tilex : tilex; + int sty = tflipy ? 1 - tiley : tiley; + + int destX = (mapx << 4) + (stx << 3); + int destY = (mapy << 4) + (sty << 3); + + bool reallyFlipX = (sflipx[tiley][tilex] ^ tflipx); + bool reallyFlipY = (sflipy[tiley][tilex] ^ tflipy); + + Magick::PixelPacket* pixels = view.get(destX,destY,8,8); + + for (int ty=0; ty<8; ty++) { + int actualTy = reallyFlipY ? (7-ty) : ty; + + for (int tx=0; tx<8; tx++) { + int actualTx = reallyFlipX ? (7-tx) : tx; + + if (tileData[actualTx][actualTy] != 0) { + //auto& c = palette.Colors().at(tileData[actualTx][actualTy]); + //std::cout << c.redQuantum() << "," << c.greenQuantum() << "," << c.blueQuantum() << std::endl; + *pixels = palette.Colors().at(tileData[actualTx][actualTy]); + //std::cout << tileData[actualTx][actualTy] << std::endl; + } + pixels++; + } + } + + view.sync(); + } + } + } + } + } + + image.magick("png"); + image.write("out.png"); } \ No newline at end of file -- cgit 1.4.1