summary refs log tree commit diff stats
path: root/tools/sprite_dumper
diff options
context:
space:
mode:
Diffstat (limited to 'tools/sprite_dumper')
-rw-r--r--tools/sprite_dumper/common.h21
-rw-r--r--tools/sprite_dumper/sprite_dumper.cpp21
-rw-r--r--tools/sprite_dumper/tileset_dumper.cpp217
3 files changed, 215 insertions, 44 deletions
diff --git a/tools/sprite_dumper/common.h b/tools/sprite_dumper/common.h index dca5de9..2aca4fa 100644 --- a/tools/sprite_dumper/common.h +++ b/tools/sprite_dumper/common.h
@@ -136,4 +136,25 @@ private:
136 std::vector<char> data_; 136 std::vector<char> data_;
137}; 137};
138 138
139class Palette {
140public:
141
142 Palette() = default;
143
144 Palette(BufferView m3, const int addr) {
145 for (int i=0; i<16; i++) {
146 unsigned short ch = m3.ReadTwoBytes(addr + (i << 1));
147 int r = (ch & 0x1F);
148 int g = ((ch >> 5) & 0x1F);
149 int b = ((ch >> 10) & 0x1F);
150 colors_.push_back(Magick::ColorRGB((r << 3)/256.0, (g << 3)/256.0, (b << 3)/256.0));
151 }
152 }
153
154 const std::vector<Magick::Color>& Colors() const { return colors_; }
155
156private:
157 std::vector<Magick::Color> colors_;
158};
159
139#endif /* end of include guard: COMMON_H_04DD2B2A */ 160#endif /* end of include guard: COMMON_H_04DD2B2A */
diff --git a/tools/sprite_dumper/sprite_dumper.cpp b/tools/sprite_dumper/sprite_dumper.cpp index 9ee55cb..392f345 100644 --- a/tools/sprite_dumper/sprite_dumper.cpp +++ b/tools/sprite_dumper/sprite_dumper.cpp
@@ -10,27 +10,6 @@
10#include <sstream> 10#include <sstream>
11#include "common.h" 11#include "common.h"
12 12
13class Palette {
14public:
15
16 Palette() = default;
17
18 Palette(BufferView m3, const int addr) {
19 for (int i=0; i<16; i++) {
20 unsigned short ch = m3.ReadTwoBytes(addr + (i << 1));
21 int r = (ch & 0x1F);
22 int g = ((ch >> 5) & 0x1F);
23 int b = ((ch >> 10) & 0x1F);
24 colors_.push_back(Magick::ColorRGB((r << 3)/256.0, (g << 3)/256.0, (b << 3)/256.0));
25 }
26 }
27
28 const std::vector<Magick::Color>& Colors() const { return colors_; }
29
30private:
31 std::vector<Magick::Color> colors_;
32};
33
34class PaletteSet { 13class PaletteSet {
35public: 14public:
36 PaletteSet(BufferView m3) : m3_(m3) { 15 PaletteSet(BufferView m3) : m3_(m3) {
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 @@
5#include <map> 5#include <map>
6#include "common.h" 6#include "common.h"
7 7
8const int NUM_ROOMS = 1000; 8constexpr int NUM_ROOMS = 1000;
9constexpr int NUM_TILESETS = 12;
9 10
10struct RoomInfo { 11struct RoomInfo {
11 int width; 12 int width;
@@ -28,6 +29,79 @@ struct RoomInfo {
28 } 29 }
29}; 30};
30 31
32struct RoomGfxPal {
33 int paletteId;
34 int tilesetId[NUM_TILESETS];
35
36 static std::map<int, RoomGfxPal> ReadFromRom(BufferView m3) {
37 const int BASE_ADDR = 0xD34F44 + 12;
38 const int ENTRY_LEN = 26;
39
40 std::map<int, RoomGfxPal> output;
41
42 for (int i=0; i<NUM_ROOMS; i++) {
43 RoomGfxPal& rgp = output[i];
44
45 rgp.paletteId = static_cast<short>(m3.ReadTwoBytes(BASE_ADDR + i*ENTRY_LEN + 24));
46 for (int tid=0; tid<NUM_TILESETS; tid++) {
47 rgp.tilesetId[tid] = m3.ReadTwoBytes(BASE_ADDR + i*ENTRY_LEN + tid*2);
48 }
49 }
50
51 return output;
52 }
53
54 std::vector<std::vector<char>> GetTilesets(BufferView m3) const {
55 const int BASE_ADDR = 0xD3B4E0;
56
57 std::vector<std::vector<char>> output(NUM_TILESETS);
58
59 for (int i=0; i<NUM_TILESETS; i++) {
60 if (tilesetId[i] < (NUM_ROOMS * 3)) {
61 unsigned long gfxAddr = m3.ReadFourBytes(BASE_ADDR + 4 + (tilesetId[i] << 2)) + BASE_ADDR;
62 output[i] = m3.Decompress(gfxAddr);
63 }
64 }
65
66 return output;
67 }
68
69 std::vector<Palette> GetPalettes(BufferView m3) const {
70 const int BASE_ADDR = 0xF3C344;
71
72 std::vector<Palette> output;
73 int offset = m3.ReadFourBytes(BASE_ADDR + 4 + (paletteId << 2));
74
75 for (int i=0; i<16; i++) {
76 unsigned long palAddr = BASE_ADDR + offset + (i << 5);
77 output.emplace_back(m3, palAddr);
78 }
79
80 return output;
81 }
82};
83
84std::vector<char> GetMapTiles(BufferView m3, int roomId) {
85 const int BASE_ADDR = 0x104D9CC;
86 int tilesAddr = m3.ReadFourBytes(BASE_ADDR + 4 + (roomId << 2)) + BASE_ADDR;
87 return m3.Decompress(tilesAddr);
88}
89
90std::vector<std::vector<char>> GetMapLayers(BufferView m3, int roomId) {
91 const int BASE_ADDR = 0xF9003C;
92 std::vector<std::vector<char>> layers;
93 for (int i=0; i<3; i++) {
94 try {
95 int lookAddr = BASE_ADDR + 4 + (((roomId * 3) + i) << 2);
96 int layerAddr = m3.ReadFourBytes(lookAddr) + BASE_ADDR;
97 layers.push_back(m3.Decompress(layerAddr));
98 } catch (const std::domain_error&) {
99 // ignore
100 }
101 }
102 return layers;
103}
104
31int main(int argc, char** argv) { 105int main(int argc, char** argv) {
32 if (argc < 3) { 106 if (argc < 3) {
33 std::cout << "Usage: ./tileset_dumper [path to rom] {map ID}" << std::endl; 107 std::cout << "Usage: ./tileset_dumper [path to rom] {map ID}" << std::endl;
@@ -37,29 +111,126 @@ int main(int argc, char** argv) {
37 Magick::InitializeMagick(nullptr); 111 Magick::InitializeMagick(nullptr);
38 112
39 Rom m3(argv[1]); 113 Rom m3(argv[1]);
114 auto roomInfos = RoomInfo::ReadFromRom(m3.buffer());
115 auto roomGfxPals = RoomGfxPal::ReadFromRom(m3.buffer());
40 116
41 int roomNum = std::stoi(argv[2]); 117 int roomNum = std::stoi(argv[2]);
42 auto roomInfos = RoomInfo::ReadFromRom(m3.buffer()); 118
43 std::cout << roomInfos[roomNum].width << "," << roomInfos[roomNum].height << std::endl; 119 std::cout << roomInfos[roomNum].width << "," << roomInfos[roomNum].height << std::endl;
44 /*const unsigned long ROOM_TILES_BASE = 0x104D9CC; 120 std::cout << roomGfxPals[roomNum].paletteId;
45 unsigned long metatilesInfoAddr = ROOM_TILES_BASE + 4 + (roomNum << 2); 121 for (int i=0;i<12;i++) std::cout << "," << roomGfxPals[roomNum].tilesetId[i];
46 unsigned long metatilesOffset = m3.buffer().ReadFourBytes(metatilesInfoAddr); 122 std::cout << std::endl;
47 unsigned long metatilesAddr = metatilesOffset + ROOM_TILES_BASE; 123
48 std::vector<char> metatiles = m3.buffer().Decompress(metatilesAddr); 124 int width = roomInfos[roomNum].width;
49 std::cout << (metatiles.size()/8) << std::endl; 125 int height = roomInfos[roomNum].height;
50 126
51 for (int i=0; i<10; i++) { 127 Magick::Image image(Magick::Geometry(width*16, height*16), "transparent");
52 int tile00 = metatiles[i*8+4]; 128 image.modifyImage();
53 int tile01 = metatiles[i*8+5]; 129 Magick::Pixels view(image);
54 int tile10 = metatiles[i*8+6]; 130
55 int tile11 = metatiles[i*8+7]; 131 auto mapTiles = GetMapTiles(m3.buffer(), roomNum);
56 132 auto mapLayers = GetMapLayers(m3.buffer(), roomNum);
57 int mask = metatiles[i*8+2]; 133
58 if ((mask & 0x1) == 0) tile00 = -1; 134 const auto& gfxPal = roomGfxPals[roomNum];
59 if ((mask & 0x2) == 0) tile01 = -1; 135 auto palettes = gfxPal.GetPalettes(m3.buffer());
60 if ((mask & 0x4) == 0) tile10 = -1; 136 auto tilesets = gfxPal.GetTilesets(m3.buffer());
61 if ((mask & 0x8) == 0) tile11 = -1; 137
62 138 for (int layer=mapLayers.size()-1; layer>=0; layer--) {
63 std::cout << tile00 << "," << tile01 << "," << tile10 << "," << tile11 << std::endl; 139 const std::vector<char>& ml = mapLayers[layer];
64 }*/ 140 if (ml.empty()) continue;
141
142 for (int mapy = 0; mapy < height; mapy++) {
143 for (int mapx = 0; mapx < width; mapx++) {
144 unsigned short ch = BufferView(ml).ReadTwoBytes((mapx + (mapy * width)) * 2);
145 unsigned short tile16 = ch & 0x3FF;
146
147 if ((tile16 >> 6) >= 12) continue;
148
149 int tpal = (ch >> 10) & 0xF;
150 const Palette& palette = palettes[tpal];
151
152 bool tflipx = (ch & 0x4000) != 0;
153 bool tflipy = (ch & 0x8000) != 0;
154
155 int tile8[2][2];
156 bool sflipx[2][2];
157 bool sflipy[2][2];
158
159 unsigned int magic = BufferView(mapTiles).ReadFourBytes(tile16 * 8);
160
161 tile8[0][0] = mapTiles[(tile16 * 8) + 4];
162 tile8[0][1] = mapTiles[(tile16 * 8) + 5];
163 tile8[1][0] = mapTiles[(tile16 * 8) + 6];
164 tile8[1][1] = mapTiles[(tile16 * 8) + 7];
165
166 for (int i=0; i<2; i++) {
167 for (int j=0; j<2; j++) {
168 sflipx[i][j] = (tile8[i][j] & 0x40) != 0;
169 sflipy[i][j] = (tile8[i][j] & 0x80) != 0;
170
171 tile8[i][j] &= 0x3f;
172 tile8[i][j] |= (ch & 0x3c0);
173 }
174 }
175
176 unsigned int mask = (magic >> 16) & 0xf;
177 if ((mask & 0x1) == 0) tile8[0][0] = -1;
178 if ((mask & 0x2) == 0) tile8[0][1] = -1;
179 if ((mask & 0x4) == 0) tile8[1][0] = -1;
180 if ((mask & 0x8) == 0) tile8[1][1] = -1;
181
182 for (int tiley=0; tiley<2; tiley++) {
183 for (int tilex=0; tilex<2; tilex++) {
184 if (tile8[tiley][tilex] < 0) continue;
185
186 int tileset = tile8[tiley][tilex] >> 6;
187 int subtile = tile8[tiley][tilex] & 0x3f;
188
189 int tileData[8][8];
190 BufferView tilesetData(tilesets[tileset]);
191 tilesetData.Seek(subtile << 5);
192 for (int ty=0; ty<8; ty++) {
193 for (int tx=0; tx<4; tx++) {
194 unsigned char vvvv = tilesetData.ReadNextByte();
195 tileData[tx*2][ty] = static_cast<unsigned char>(vvvv & 0xF);
196 tileData[tx*2+1][ty] = static_cast<unsigned char>((vvvv >> 4) & 0xF);
197 }
198 }
199
200 int stx = tflipx ? 1 - tilex : tilex;
201 int sty = tflipy ? 1 - tiley : tiley;
202
203 int destX = (mapx << 4) + (stx << 3);
204 int destY = (mapy << 4) + (sty << 3);
205
206 bool reallyFlipX = (sflipx[tiley][tilex] ^ tflipx);
207 bool reallyFlipY = (sflipy[tiley][tilex] ^ tflipy);
208
209 Magick::PixelPacket* pixels = view.get(destX,destY,8,8);
210
211 for (int ty=0; ty<8; ty++) {
212 int actualTy = reallyFlipY ? (7-ty) : ty;
213
214 for (int tx=0; tx<8; tx++) {
215 int actualTx = reallyFlipX ? (7-tx) : tx;
216
217 if (tileData[actualTx][actualTy] != 0) {
218 //auto& c = palette.Colors().at(tileData[actualTx][actualTy]);
219 //std::cout << c.redQuantum() << "," << c.greenQuantum() << "," << c.blueQuantum() << std::endl;
220 *pixels = palette.Colors().at(tileData[actualTx][actualTy]);
221 //std::cout << tileData[actualTx][actualTy] << std::endl;
222 }
223 pixels++;
224 }
225 }
226
227 view.sync();
228 }
229 }
230 }
231 }
232 }
233
234 image.magick("png");
235 image.write("out.png");
65} \ No newline at end of file 236} \ No newline at end of file