diff options
Diffstat (limited to 'tools/sprite_dumper')
| -rw-r--r-- | tools/sprite_dumper/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | tools/sprite_dumper/common.h | 139 | ||||
| -rw-r--r-- | tools/sprite_dumper/sprite_dumper.cpp (renamed from tools/sprite_dumper/main.cpp) | 106 | ||||
| -rw-r--r-- | tools/sprite_dumper/tileset_dumper.cpp | 39 |
4 files changed, 199 insertions, 93 deletions
| diff --git a/tools/sprite_dumper/CMakeLists.txt b/tools/sprite_dumper/CMakeLists.txt index 5a90c5e..62f4a28 100644 --- a/tools/sprite_dumper/CMakeLists.txt +++ b/tools/sprite_dumper/CMakeLists.txt | |||
| @@ -8,8 +8,12 @@ pkg_check_modules(GraphicsMagick GraphicsMagick++ REQUIRED) | |||
| 8 | 8 | ||
| 9 | include_directories(${GraphicsMagick_INCLUDE_DIRS}) | 9 | include_directories(${GraphicsMagick_INCLUDE_DIRS}) |
| 10 | 10 | ||
| 11 | add_executable(sprite_dumper main.cpp) | 11 | add_executable(sprite_dumper sprite_dumper.cpp) |
| 12 | |||
| 13 | set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD 17) | 12 | set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD 17) |
| 14 | set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD_REQUIRED ON) | 13 | set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD_REQUIRED ON) |
| 15 | target_link_libraries(sprite_dumper ${GraphicsMagick_LIBRARIES}) | 14 | target_link_libraries(sprite_dumper ${GraphicsMagick_LIBRARIES}) |
| 15 | |||
| 16 | add_executable(tileset_dumper tileset_dumper.cpp) | ||
| 17 | set_property(TARGET tileset_dumper PROPERTY CXX_STANDARD 17) | ||
| 18 | set_property(TARGET tileset_dumper PROPERTY CXX_STANDARD_REQUIRED ON) | ||
| 19 | target_link_libraries(tileset_dumper ${GraphicsMagick_LIBRARIES}) | ||
| diff --git a/tools/sprite_dumper/common.h b/tools/sprite_dumper/common.h new file mode 100644 index 0000000..dca5de9 --- /dev/null +++ b/tools/sprite_dumper/common.h | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | #ifndef COMMON_H_04DD2B2A | ||
| 2 | #define COMMON_H_04DD2B2A | ||
| 3 | |||
| 4 | #include <vector> | ||
| 5 | #include <string_view> | ||
| 6 | #include <fstream> | ||
| 7 | #include <stdexcept> | ||
| 8 | |||
| 9 | class BufferView { | ||
| 10 | public: | ||
| 11 | |||
| 12 | BufferView(const std::vector<char>& buffer) : data_(&buffer) {} | ||
| 13 | |||
| 14 | int ReadNextByte() { | ||
| 15 | int o2r = offset_; | ||
| 16 | offset_++; | ||
| 17 | return ReadByte(o2r); | ||
| 18 | } | ||
| 19 | |||
| 20 | int ReadByte(int addr) const { | ||
| 21 | return static_cast<unsigned char>((*data_)[addr]); | ||
| 22 | } | ||
| 23 | |||
| 24 | int ReadNextTwoBytes() { | ||
| 25 | int o2r = offset_; | ||
| 26 | offset_+=2; | ||
| 27 | return ReadTwoBytes(o2r); | ||
| 28 | } | ||
| 29 | |||
| 30 | int ReadTwoBytes(int addr) const { | ||
| 31 | return static_cast<unsigned char>((*data_)[addr]) | (static_cast<unsigned char>((*data_)[addr + 1]) << 8); | ||
| 32 | } | ||
| 33 | |||
| 34 | int ReadNextFourBytes() { | ||
| 35 | int o2r = offset_; | ||
| 36 | offset_+=4; | ||
| 37 | return ReadFourBytes(o2r); | ||
| 38 | } | ||
| 39 | |||
| 40 | unsigned long ReadFourBytes(int addr) const { | ||
| 41 | return static_cast<unsigned char>((*data_)[addr]) | (static_cast<unsigned char>((*data_)[addr + 1]) << 8) | (static_cast<unsigned char>((*data_)[addr + 2]) << 16) | (static_cast<unsigned char>((*data_)[addr + 3]) << 24); | ||
| 42 | } | ||
| 43 | |||
| 44 | void Seek(int offset) { | ||
| 45 | offset_ = offset; | ||
| 46 | } | ||
| 47 | |||
| 48 | void SeekAdd(int delta) { | ||
| 49 | offset_ += delta; | ||
| 50 | } | ||
| 51 | |||
| 52 | std::vector<char> Decompress(int addr) { | ||
| 53 | int start = addr; | ||
| 54 | Seek(addr); | ||
| 55 | if (ReadNextByte() != 0x10) { | ||
| 56 | throw std::domain_error("No LZ77 signature"); | ||
| 57 | } | ||
| 58 | |||
| 59 | int length = ReadNextByte(); | ||
| 60 | length += (ReadNextByte() << 8); | ||
| 61 | length += (ReadNextByte() << 16); | ||
| 62 | |||
| 63 | std::vector<char> result(length, 0); | ||
| 64 | |||
| 65 | int bPos = 0; | ||
| 66 | while (bPos < length) { | ||
| 67 | unsigned char ch = ReadNextByte(); | ||
| 68 | for (int i=0;i<8;i++) { | ||
| 69 | switch ((ch >> (7-i)) & 1) { | ||
| 70 | case 0: { | ||
| 71 | if (bPos >= length) break; | ||
| 72 | result[bPos++] = ReadNextByte(); | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | case 1: { | ||
| 76 | int t = (ReadNextByte() << 8); | ||
| 77 | t += ReadNextByte(); | ||
| 78 | int n = ((t >> 12) & 0xF) + 3; // num of bytes to copy | ||
| 79 | int o = (t & 0xFFF); | ||
| 80 | |||
| 81 | memcpy(result.data() + bPos, result.data() + bPos - o - 1, n); | ||
| 82 | bPos += n; | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | default: break; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 93 | private: | ||
| 94 | |||
| 95 | const std::vector<char>* data_; | ||
| 96 | int offset_ = 0; | ||
| 97 | }; | ||
| 98 | |||
| 99 | class Rom { | ||
| 100 | public: | ||
| 101 | |||
| 102 | explicit Rom(std::string_view filename) { | ||
| 103 | std::ifstream romfile(filename.data(), std::ios::binary); | ||
| 104 | if (!romfile.is_open()) { | ||
| 105 | throw std::invalid_argument("Could not find ROM file: " + std::string(filename)); | ||
| 106 | } | ||
| 107 | |||
| 108 | romfile.seekg(0, romfile.end); | ||
| 109 | int length = romfile.tellg(); | ||
| 110 | romfile.seekg(0, romfile.beg); | ||
| 111 | |||
| 112 | if (length != 0x2000000) { | ||
| 113 | throw std::invalid_argument("Incorrect ROM length"); | ||
| 114 | } | ||
| 115 | |||
| 116 | data_ = std::vector<char>(length, 0); | ||
| 117 | romfile.read(data_.data(), length); | ||
| 118 | |||
| 119 | const char header[] = {'M','O','T','H','E','R','3',0,0,0,0,0,'A','3','U','J'}; | ||
| 120 | std::string headerTest; | ||
| 121 | for (int i = 0xA0; i < 0xB0; i++) { | ||
| 122 | if (data_.at(i) != header[i-0xA0]) { | ||
| 123 | std::cout << i << std::endl; | ||
| 124 | |||
| 125 | throw std::invalid_argument("Invalid ROM header"); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | const std::vector<char>& data() const { return data_; } | ||
| 131 | |||
| 132 | BufferView buffer() const { return {data_}; } | ||
| 133 | |||
| 134 | private: | ||
| 135 | |||
| 136 | std::vector<char> data_; | ||
| 137 | }; | ||
| 138 | |||
| 139 | #endif /* end of include guard: COMMON_H_04DD2B2A */ | ||
| diff --git a/tools/sprite_dumper/main.cpp b/tools/sprite_dumper/sprite_dumper.cpp index 2ba37c8..9ee55cb 100644 --- a/tools/sprite_dumper/main.cpp +++ b/tools/sprite_dumper/sprite_dumper.cpp | |||
| @@ -8,90 +8,14 @@ | |||
| 8 | #include <iostream> | 8 | #include <iostream> |
| 9 | #include <Magick++.h> | 9 | #include <Magick++.h> |
| 10 | #include <sstream> | 10 | #include <sstream> |
| 11 | 11 | #include "common.h" | |
| 12 | class Rom { | ||
| 13 | public: | ||
| 14 | |||
| 15 | explicit Rom(std::string_view filename) { | ||
| 16 | std::ifstream romfile(filename.data(), std::ios::binary); | ||
| 17 | if (!romfile.is_open()) { | ||
| 18 | throw std::invalid_argument("Could not find ROM file: " + std::string(filename)); | ||
| 19 | } | ||
| 20 | |||
| 21 | romfile.seekg(0, romfile.end); | ||
| 22 | int length = romfile.tellg(); | ||
| 23 | romfile.seekg(0, romfile.beg); | ||
| 24 | |||
| 25 | if (length != 0x2000000) { | ||
| 26 | throw std::invalid_argument("Incorrect ROM length"); | ||
| 27 | } | ||
| 28 | |||
| 29 | data_ = std::vector<char>(length, 0); | ||
| 30 | romfile.read(data_.data(), length); | ||
| 31 | |||
| 32 | const char header[] = {'M','O','T','H','E','R','3',0,0,0,0,0,'A','3','U','J'}; | ||
| 33 | std::string headerTest; | ||
| 34 | for (int i = 0xA0; i < 0xB0; i++) { | ||
| 35 | if (data_.at(i) != header[i-0xA0]) { | ||
| 36 | std::cout << i << std::endl; | ||
| 37 | |||
| 38 | throw std::invalid_argument("Invalid ROM header"); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | const std::vector<char>& data() const { return data_; } | ||
| 44 | |||
| 45 | int ReadNextByte() { | ||
| 46 | int o2r = offset_; | ||
| 47 | offset_++; | ||
| 48 | return ReadByte(o2r); | ||
| 49 | } | ||
| 50 | |||
| 51 | int ReadByte(int addr) const { | ||
| 52 | return static_cast<unsigned char>(data_[addr]); | ||
| 53 | } | ||
| 54 | |||
| 55 | int ReadNextTwoBytes() { | ||
| 56 | int o2r = offset_; | ||
| 57 | offset_+=2; | ||
| 58 | return ReadTwoBytes(o2r); | ||
| 59 | } | ||
| 60 | |||
| 61 | int ReadTwoBytes(int addr) const { | ||
| 62 | return static_cast<unsigned char>(data_[addr]) | (static_cast<unsigned char>(data_[addr + 1]) << 8); | ||
| 63 | } | ||
| 64 | |||
| 65 | int ReadNextFourBytes() { | ||
| 66 | int o2r = offset_; | ||
| 67 | offset_+=4; | ||
| 68 | return ReadFourBytes(o2r); | ||
| 69 | } | ||
| 70 | |||
| 71 | unsigned long ReadFourBytes(int addr) const { | ||
| 72 | return static_cast<unsigned char>(data_[addr]) | (static_cast<unsigned char>(data_[addr + 1]) << 8) | (static_cast<unsigned char>(data_[addr + 2]) << 16) | (static_cast<unsigned char>(data_[addr + 3]) << 24); | ||
| 73 | } | ||
| 74 | |||
| 75 | void Seek(int offset) { | ||
| 76 | offset_ = offset; | ||
| 77 | } | ||
| 78 | |||
| 79 | void SeekAdd(int delta) { | ||
| 80 | offset_ += delta; | ||
| 81 | } | ||
| 82 | |||
| 83 | private: | ||
| 84 | |||
| 85 | std::vector<char> data_; | ||
| 86 | int offset_ = 0; | ||
| 87 | }; | ||
| 88 | 12 | ||
| 89 | class Palette { | 13 | class Palette { |
| 90 | public: | 14 | public: |
| 91 | 15 | ||
| 92 | Palette() = default; | 16 | Palette() = default; |
| 93 | 17 | ||
| 94 | Palette(Rom& m3, const int addr) { | 18 | Palette(BufferView m3, const int addr) { |
| 95 | for (int i=0; i<16; i++) { | 19 | for (int i=0; i<16; i++) { |
| 96 | unsigned short ch = m3.ReadTwoBytes(addr + (i << 1)); | 20 | unsigned short ch = m3.ReadTwoBytes(addr + (i << 1)); |
| 97 | int r = (ch & 0x1F); | 21 | int r = (ch & 0x1F); |
| @@ -109,7 +33,7 @@ private: | |||
| 109 | 33 | ||
| 110 | class PaletteSet { | 34 | class PaletteSet { |
| 111 | public: | 35 | public: |
| 112 | PaletteSet(Rom& m3) : m3_(m3) { | 36 | PaletteSet(BufferView m3) : m3_(m3) { |
| 113 | for (int i=0; i<16; i++) { | 37 | for (int i=0; i<16; i++) { |
| 114 | defaultPals_.emplace_back(m3, GetPointer(0) + (i << 5)); | 38 | defaultPals_.emplace_back(m3, GetPointer(0) + (i << 5)); |
| 115 | } | 39 | } |
| @@ -147,7 +71,7 @@ private: | |||
| 147 | return ADDR + a; | 71 | return ADDR + a; |
| 148 | } | 72 | } |
| 149 | 73 | ||
| 150 | Rom& m3_; | 74 | BufferView m3_; |
| 151 | std::vector<Palette> defaultPals_; | 75 | std::vector<Palette> defaultPals_; |
| 152 | std::map<int, Palette> specialPals_; | 76 | std::map<int, Palette> specialPals_; |
| 153 | }; | 77 | }; |
| @@ -182,7 +106,7 @@ struct FrameOutput { | |||
| 182 | struct Sprite { | 106 | struct Sprite { |
| 183 | std::vector<Subsprite> subsprites; | 107 | std::vector<Subsprite> subsprites; |
| 184 | 108 | ||
| 185 | FrameOutput render(Rom& m3, const Palette& palette, const int gfxPtr) const { | 109 | FrameOutput render(BufferView m3, const Palette& palette, const int gfxPtr) const { |
| 186 | FrameOutput output; | 110 | FrameOutput output; |
| 187 | 111 | ||
| 188 | if (subsprites.empty()) return output; | 112 | if (subsprites.empty()) return output; |
| @@ -271,7 +195,7 @@ struct SpriteSheet { | |||
| 271 | int gfxPtr; | 195 | int gfxPtr; |
| 272 | std::vector<Sprite> sprites; | 196 | std::vector<Sprite> sprites; |
| 273 | 197 | ||
| 274 | void render(Rom& m3, PaletteSet& palettes, std::vector<FrameOutput>& frames) const { | 198 | void render(BufferView m3, PaletteSet& palettes, std::vector<FrameOutput>& frames) const { |
| 275 | const Palette& palette = palettes.GetPalette(spriteindex); | 199 | const Palette& palette = palettes.GetPalette(spriteindex); |
| 276 | for (int i=0; i<sprites.size(); i++) { | 200 | for (int i=0; i<sprites.size(); i++) { |
| 277 | FrameOutput f = sprites[i].render(m3, palette, gfxPtr); | 201 | FrameOutput f = sprites[i].render(m3, palette, gfxPtr); |
| @@ -283,7 +207,7 @@ struct SpriteSheet { | |||
| 283 | class Bank { | 207 | class Bank { |
| 284 | public: | 208 | public: |
| 285 | 209 | ||
| 286 | Bank(Rom& m3, const int baseAddr, const int gfxAddr) : baseAddr_(baseAddr), gfxAddr_(gfxAddr) { | 210 | Bank(BufferView m3, const int baseAddr, const int gfxAddr) : baseAddr_(baseAddr), gfxAddr_(gfxAddr) { |
| 287 | int numEntries = m3.ReadFourBytes(baseAddr); | 211 | int numEntries = m3.ReadFourBytes(baseAddr); |
| 288 | std::cout << numEntries << std::endl; | 212 | std::cout << numEntries << std::endl; |
| 289 | 213 | ||
| @@ -337,7 +261,7 @@ public: | |||
| 337 | 261 | ||
| 338 | private: | 262 | private: |
| 339 | 263 | ||
| 340 | int GetPointerToSheet(Rom& m3, int index) { | 264 | int GetPointerToSheet(BufferView m3, int index) { |
| 341 | int readAt = baseAddr_ + 4 + (index << 2); | 265 | int readAt = baseAddr_ + 4 + (index << 2); |
| 342 | int a = m3.ReadFourBytes(readAt); | 266 | int a = m3.ReadFourBytes(readAt); |
| 343 | //std::cout << readAt << " :: " << a << std::hex << std::endl; | 267 | //std::cout << readAt << " :: " << a << std::hex << std::endl; |
| @@ -345,7 +269,7 @@ private: | |||
| 345 | return a + baseAddr_; | 269 | return a + baseAddr_; |
| 346 | } | 270 | } |
| 347 | 271 | ||
| 348 | int GetGfxPointer(Rom& m3, int index) { | 272 | int GetGfxPointer(BufferView m3, int index) { |
| 349 | return m3.ReadFourBytes(gfxAddr_ + 4 + (index << 2)) + gfxAddr_; | 273 | return m3.ReadFourBytes(gfxAddr_ + 4 + (index << 2)) + gfxAddr_; |
| 350 | } | 274 | } |
| 351 | 275 | ||
| @@ -365,11 +289,11 @@ int main(int argc, char** argv) { | |||
| 365 | Magick::InitializeMagick(nullptr); | 289 | Magick::InitializeMagick(nullptr); |
| 366 | 290 | ||
| 367 | Rom m3(argv[1]); | 291 | Rom m3(argv[1]); |
| 368 | PaletteSet palettes(m3); | 292 | PaletteSet palettes(m3.buffer()); |
| 369 | Bank b1(m3, 0x1A442A4, 0x14383E4); | 293 | Bank b1(m3.buffer(), 0x1A442A4, 0x14383E4); |
| 370 | Bank b2(m3, 0x1AE0638, 0x194BC30); | 294 | Bank b2(m3.buffer(), 0x1AE0638, 0x194BC30); |
| 371 | Bank b3(m3, 0x1AEE4C4, 0x1A012B8); | 295 | Bank b3(m3.buffer(), 0x1AEE4C4, 0x1A012B8); |
| 372 | Bank b4(m3, 0x1AF1ED0, 0x1A36AA0); | 296 | Bank b4(m3.buffer(), 0x1AF1ED0, 0x1A36AA0); |
| 373 | 297 | ||
| 374 | std::vector<FrameOutput> frames; | 298 | std::vector<FrameOutput> frames; |
| 375 | 299 | ||
| @@ -394,7 +318,7 @@ int main(int argc, char** argv) { | |||
| 394 | } | 318 | } |
| 395 | }(); | 319 | }(); |
| 396 | 320 | ||
| 397 | bankToRead.SpriteSheets().at(sheetNum).render(m3, palettes, frames); | 321 | bankToRead.SpriteSheets().at(sheetNum).render(m3.buffer(), palettes, frames); |
| 398 | } | 322 | } |
| 399 | 323 | ||
| 400 | int maxWidth = 0; | 324 | int maxWidth = 0; |
| diff --git a/tools/sprite_dumper/tileset_dumper.cpp b/tools/sprite_dumper/tileset_dumper.cpp new file mode 100644 index 0000000..10e46fa --- /dev/null +++ b/tools/sprite_dumper/tileset_dumper.cpp | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #include <iostream> | ||
| 2 | #include <Magick++.h> | ||
| 3 | #include <vector> | ||
| 4 | #include <string> | ||
| 5 | #include "common.h" | ||
| 6 | |||
| 7 | int main(int argc, char** argv) { | ||
| 8 | if (argc < 3) { | ||
| 9 | std::cout << "Usage: ./tileset_dumper [path to rom] {map ID}" << std::endl; | ||
| 10 | return -1; | ||
| 11 | } | ||
| 12 | |||
| 13 | Magick::InitializeMagick(nullptr); | ||
| 14 | |||
| 15 | Rom m3(argv[1]); | ||
| 16 | |||
| 17 | int roomNum = std::stoi(argv[2]); | ||
| 18 | const unsigned long ROOM_TILES_BASE = 0x104D9CC; | ||
| 19 | unsigned long metatilesInfoAddr = ROOM_TILES_BASE + 4 + (roomNum << 2); | ||
| 20 | unsigned long metatilesOffset = m3.buffer().ReadFourBytes(metatilesInfoAddr); | ||
| 21 | unsigned long metatilesAddr = metatilesOffset + ROOM_TILES_BASE; | ||
| 22 | std::vector<char> metatiles = m3.buffer().Decompress(metatilesAddr); | ||
| 23 | std::cout << (metatiles.size()/8) << std::endl; | ||
| 24 | |||
| 25 | for (int i=0; i<10; i++) { | ||
| 26 | int tile00 = metatiles[i*8+4]; | ||
| 27 | int tile01 = metatiles[i*8+5]; | ||
| 28 | int tile10 = metatiles[i*8+6]; | ||
| 29 | int tile11 = metatiles[i*8+7]; | ||
| 30 | |||
| 31 | int mask = metatiles[i*8+2]; | ||
| 32 | if ((mask & 0x1) == 0) tile00 = -1; | ||
| 33 | if ((mask & 0x2) == 0) tile01 = -1; | ||
| 34 | if ((mask & 0x4) == 0) tile10 = -1; | ||
| 35 | if ((mask & 0x8) == 0) tile11 = -1; | ||
| 36 | |||
| 37 | std::cout << tile00 << "," << tile01 << "," << tile10 << "," << tile11 << std::endl; | ||
| 38 | } | ||
| 39 | } \ No newline at end of file | ||
