summary refs log tree commit diff stats
path: root/tools/sprite_dumper
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2021-01-31 20:04:51 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2021-01-31 20:04:51 -0500
commita64c85a3f5641581a19ef52a5c7898ec3cb71754 (patch)
tree8df10037fa552887966d9f0d5b147e0fd35abbf4 /tools/sprite_dumper
parent66e8f5b7d5d245bb7f5d4c4963e70e6b97e0bd4d (diff)
downloadtanetane-a64c85a3f5641581a19ef52a5c7898ec3cb71754.tar.gz
tanetane-a64c85a3f5641581a19ef52a5c7898ec3cb71754.tar.bz2
tanetane-a64c85a3f5641581a19ef52a5c7898ec3cb71754.zip
Abstracted some of the sprite dumper functionality out
Diffstat (limited to 'tools/sprite_dumper')
-rw-r--r--tools/sprite_dumper/CMakeLists.txt8
-rw-r--r--tools/sprite_dumper/common.h139
-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.cpp39
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
9include_directories(${GraphicsMagick_INCLUDE_DIRS}) 9include_directories(${GraphicsMagick_INCLUDE_DIRS})
10 10
11add_executable(sprite_dumper main.cpp) 11add_executable(sprite_dumper sprite_dumper.cpp)
12
13set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD 17) 12set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD 17)
14set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD_REQUIRED ON) 13set_property(TARGET sprite_dumper PROPERTY CXX_STANDARD_REQUIRED ON)
15target_link_libraries(sprite_dumper ${GraphicsMagick_LIBRARIES}) 14target_link_libraries(sprite_dumper ${GraphicsMagick_LIBRARIES})
15
16add_executable(tileset_dumper tileset_dumper.cpp)
17set_property(TARGET tileset_dumper PROPERTY CXX_STANDARD 17)
18set_property(TARGET tileset_dumper PROPERTY CXX_STANDARD_REQUIRED ON)
19target_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
9class BufferView {
10public:
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
93private:
94
95 const std::vector<char>* data_;
96 int offset_ = 0;
97};
98
99class Rom {
100public:
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
134private:
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"
12class Rom {
13public:
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
83private:
84
85 std::vector<char> data_;
86 int offset_ = 0;
87};
88 12
89class Palette { 13class Palette {
90public: 14public:
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
110class PaletteSet { 34class PaletteSet {
111public: 35public:
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 {
182struct Sprite { 106struct 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 {
283class Bank { 207class Bank {
284public: 208public:
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
338private: 262private:
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
7int 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