yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
snes_tile.cc
Go to the documentation of this file.
1#include "snes_tile.h"
2
3#include <cassert>
4#include <cstdint>
5#include <stdexcept>
6#include <vector>
7
8#include "util/macro.h"
9
10namespace yaze {
11namespace gfx {
12
13// Bit set for object priority
14constexpr uint16_t TilePriorityBit = 0x2000;
15
16// Bit set for object hflip
17constexpr uint16_t TileHFlipBit = 0x4000;
18
19// Bit set for object vflip
20constexpr uint16_t TileVFlipBit = 0x8000;
21
22// Bits used for tile name
23constexpr uint16_t TileNameMask = 0x03FF;
24
25snes_tile8 UnpackBppTile(const std::vector<uint8_t>& data,
26 const uint32_t offset, const uint32_t bpp) {
27 snes_tile8 tile;
28 assert(bpp >= 1 && bpp <= 8);
29 unsigned int bpp_pos[8]; // More for conveniance and readibility
30 for (int col = 0; col < 8; col++) {
31 for (int row = 0; row < 8; row++) {
32 if (bpp == 1) {
33 tile.data[col * 8 + row] = (data[offset + col] >> (7 - row)) & 0x01;
34 continue;
35 }
36 /* SNES bpp format interlace each byte of the first 2 bitplanes.
37 * | byte 1 of first bitplane | byte 1 of second bitplane |
38 * | byte 2 of first bitplane | byte 2 of second bitplane | ..
39 */
40 bpp_pos[0] = offset + col * 2;
41 bpp_pos[1] = offset + col * 2 + 1;
42 char mask = 1 << (7 - row);
43 tile.data[col * 8 + row] = (data[bpp_pos[0]] & mask) == mask;
44 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[1]] & mask) == mask)
45 << 1;
46 if (bpp == 3) {
47 // When we have 3 bitplanes, the bytes for the third bitplane are after
48 // the 16 bytes of the 2 bitplanes.
49 bpp_pos[2] = offset + 16 + col;
50 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[2]] & mask) == mask)
51 << 2;
52 }
53 if (bpp >= 4) {
54 // For 4 bitplanes, the 2 added bitplanes are interlaced like the first
55 // two.
56 bpp_pos[2] = offset + 16 + col * 2;
57 bpp_pos[3] = offset + 16 + col * 2 + 1;
58 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[2]] & mask) == mask)
59 << 2;
60 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[3]] & mask) == mask)
61 << 3;
62 }
63 if (bpp == 8) {
64 bpp_pos[4] = offset + 32 + col * 2;
65 bpp_pos[5] = offset + 32 + col * 2 + 1;
66 bpp_pos[6] = offset + 48 + col * 2;
67 bpp_pos[7] = offset + 48 + col * 2 + 1;
68 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[4]] & mask) == mask)
69 << 4;
70 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[5]] & mask) == mask)
71 << 5;
72 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[6]] & mask) == mask)
73 << 6;
74 tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[7]] & mask) == mask)
75 << 7;
76 }
77 }
78 }
79 return tile;
80}
81
82std::vector<uint8_t> PackBppTile(const snes_tile8& tile, const uint32_t bpp) {
83 // Allocate memory for output data
84 std::vector<uint8_t> output(bpp * 8, 0); // initialized with 0
85 unsigned maxcolor = 2 << bpp;
86
87 // Iterate over all columns and rows of the tile
88 for (unsigned int col = 0; col < 8; col++) {
89 for (unsigned int row = 0; row < 8; row++) {
90 uint8_t color = tile.data[col * 8 + row];
91 if (color > maxcolor) {
92 throw std::invalid_argument("Invalid color value.");
93 }
94
95 // 1bpp format
96 if (bpp == 1) output[col] += (uint8_t)((color & 1) << (7 - row));
97
98 // 2bpp format
99 if (bpp >= 2) {
100 output[col * 2] += (uint8_t)((color & 1) << (7 - row));
101 output[col * 2 + 1] +=
102 (uint8_t)((uint8_t)((color & 2) == 2) << (7 - row));
103 }
104
105 // 3bpp format
106 if (bpp == 3)
107 output[16 + col] += (uint8_t)(((color & 4) == 4) << (7 - row));
108
109 // 4bpp format
110 if (bpp >= 4) {
111 output[16 + col * 2] += (uint8_t)(((color & 4) == 4) << (7 - row));
112 output[16 + col * 2 + 1] += (uint8_t)(((color & 8) == 8) << (7 - row));
113 }
114
115 // 8bpp format
116 if (bpp == 8) {
117 output[32 + col * 2] += (uint8_t)(((color & 16) == 16) << (7 - row));
118 output[32 + col * 2 + 1] +=
119 (uint8_t)(((color & 32) == 32) << (7 - row));
120 output[48 + col * 2] += (uint8_t)(((color & 64) == 64) << (7 - row));
121 output[48 + col * 2 + 1] +=
122 (uint8_t)(((color & 128) == 128) << (7 - row));
123 }
124 }
125 }
126 return output;
127}
128
129std::vector<uint8_t> ConvertBpp(const std::vector<uint8_t>& tiles,
130 uint32_t from_bpp, uint32_t to_bpp) {
131 unsigned int nb_tile = tiles.size() / (from_bpp * 8);
132 std::vector<uint8_t> converted(nb_tile * to_bpp * 8);
133
134 for (unsigned int i = 0; i < nb_tile; i++) {
135 snes_tile8 tile = UnpackBppTile(tiles, i * from_bpp * 8, from_bpp);
136 std::vector<uint8_t> packed_tile = PackBppTile(tile, to_bpp);
137 std::memcpy(converted.data() + i * to_bpp * 8, packed_tile.data(),
138 to_bpp * 8);
139 }
140 return converted;
141}
142
143std::vector<uint8_t> Convert3bppTo4bpp(const std::vector<uint8_t>& tiles) {
144 return ConvertBpp(tiles, 3, 4);
145}
146
147std::vector<uint8_t> Convert4bppTo3bpp(const std::vector<uint8_t>& tiles) {
148 return ConvertBpp(tiles, 4, 3);
149}
150
151std::vector<uint8_t> SnesTo8bppSheet(const std::vector<uint8_t>& sheet, int bpp,
152 int num_sheets) {
153 int xx = 0; // positions where we are at on the sheet
154 int yy = 0;
155 int pos = 0;
156 int ypos = 0;
157 int num_tiles = 64;
158 int buffer_size = 0x1000;
159
160 if (bpp == 2) {
161 bpp = 16;
162 num_tiles = 128;
163 buffer_size = 0x2000;
164 } else if (bpp == 3) {
165 bpp = 24;
166 } else if (bpp == 4) {
167 bpp = 32;
168 buffer_size = 0x4000;
169 } else if (bpp == 8) {
170 bpp = 64;
171 }
172
173 if (num_sheets != 1) {
174 num_tiles *= num_sheets;
175 buffer_size *= num_sheets;
176 }
177
178 std::vector<uint8_t> sheet_buffer_out(buffer_size);
179
180 for (int i = 0; i < num_tiles; i++) { // for each tiles, 16 per line
181 for (int y = 0; y < 8; y++) { // for each line
182 for (int x = 0; x < 8; x++) { //[0] + [1] + [16]
183 auto b1 = (sheet[(y * 2) + (bpp * pos)] & (kGraphicsBitmap[x]));
184 auto b2 = (sheet[((y * 2) + (bpp * pos)) + 1] & (kGraphicsBitmap[x]));
185 auto b3 = (sheet[(16 + y) + (bpp * pos)] & (kGraphicsBitmap[x]));
186 unsigned char b = 0;
187 if (b1 != 0) {
188 b |= 1;
189 }
190 if (b2 != 0) {
191 b |= 2;
192 }
193 if (b3 != 0 && bpp != 16) {
194 b |= 4;
195 }
196 sheet_buffer_out[x + xx + (y * 128) + (yy * 1024)] = b;
197 }
198 }
199 pos++;
200 ypos++;
201 xx += 8;
202 if (ypos >= 16) {
203 yy++;
204 xx = 0;
205 ypos = 0;
206 }
207 }
208 return sheet_buffer_out;
209}
210
211std::vector<uint8_t> Bpp8SnesToIndexed(std::vector<uint8_t> data,
212 uint64_t bpp) {
213 // 3BPP
214 // [r0,bp1],[r0,bp2],[r1,bp1],[r1,bp2],[r2,bp1],[r2,bp2],[r3,bp1],[r3,bp2]
215 // [r4,bp1],[r4,bp2],[r5,bp1],[r5,bp2],[r6,bp1],[r6,bp2],[r7,bp1],[r7,bp2]
216 // [r0,bp3],[r0,bp4],[r1,bp3],[r1,bp4],[r2,bp3],[r2,bp4],[r3,bp3],[r3,bp4]
217 // [r4,bp3],[r4,bp4],[r5,bp3],[r5,bp4],[r6,bp3],[r6,bp4],[r7,bp3],[r7,bp4]
218 // [r0,bp5],[r0,bp6],[r1,bp5],[r1,bp6],[r2,bp5],[r2,bp6],[r3,bp5],[r3,bp6]
219 // [r4,bp5],[r4,bp6],[r5,bp5],[r5,bp6],[r6,bp5],[r6,bp6],[r7,bp5],[r7,bp6]
220 // [r0,bp7],[r0,bp8],[r1,bp7],[r1,bp8],[r2,bp7],[r2,bp8],[r3,bp7],[r3,bp8]
221 // [r4,bp7],[r4,bp8],[r5,bp7],[r5,bp8],[r6,bp7],[r6,bp8],[r7,bp7],[r7,bp8]
222
223 // 16 tiles = 1024 bytes
224 auto buffer = std::vector<uint8_t>(data.size());
225 std::vector<std::vector<uint8_t>> bitmap_data;
226 bitmap_data.resize(0x80);
227 for (auto& each : bitmap_data) {
228 each.reserve(0x800);
229 }
230 int yy = 0;
231 int xx = 0;
232 int pos = 0;
233
234 const uint16_t sheet_width = 128;
235
236 // 64 = 4096 bytes
237 // 16 = 1024?
238 int ypos = 0;
239 // for each tiles //16 per lines
240 for (int i = 0; i < 4096; i++) {
241 // for each lines
242 for (int y = 0; y < 8; y++) {
243 //[0] + [1] + [16]
244 for (int x = 0; x < 8; x++) {
245 const uint16_t bitmask[] = {0x80, 0x40, 0x20, 0x10,
246 0x08, 0x04, 0x02, 0x01};
247 auto b1 = (data[(y * 2) + ((bpp * 8) * pos)] & (bitmask[x]));
248 auto b2 = (data[((y * 2) + ((bpp * 8) * pos)) + 1] & (bitmask[x]));
249 auto b3 = (data[(y * 2) + ((bpp * 8) * pos) + 16] & (bitmask[x]));
250 auto b4 = (data[(y * 2) + ((bpp * 8) * pos) + 17] & (bitmask[x]));
251 auto b5 = (data[(y * 2) + ((bpp * 8) * pos) + 32] & (bitmask[x]));
252 auto b6 = (data[(y * 2) + ((bpp * 8) * pos) + 33] & (bitmask[x]));
253 auto b7 = (data[(y * 2) + ((bpp * 8) * pos) + 48] & (bitmask[x]));
254 auto b8 = (data[(y * 2) + ((bpp * 8) * pos) + 49] & (bitmask[x]));
255
256 auto b = 0;
257 if (b1 != 0) {
258 b |= 1;
259 }
260 if (b2 != 0) {
261 b |= 2;
262 }
263 if (bpp >= 4) {
264 if (b3 != 0) {
265 b |= 4;
266 }
267 if (b4 != 0) {
268 b |= 8;
269 }
270 }
271 if (bpp >= 8) {
272 if (b5 != 0) {
273 b |= 0x10;
274 }
275 if (b6 != 0) {
276 b |= 0x20;
277 }
278 if (b7 != 0) {
279 b |= 0x40;
280 }
281 if (b8 != 0) {
282 b |= 0x80;
283 }
284 }
285 // bitmap_data[((x + xx) * sheet_width) + y + (yy * 8)] = b;
286 bitmap_data[x + xx][y + (yy * 8)] = b;
287 }
288 }
289 pos++;
290 ypos++;
291 xx += 8;
292 if (ypos >= 16) {
293 yy++;
294 xx = 0;
295 ypos = 0;
296 }
297 }
298
299 int n = 0;
300
301 for (int y = 0; y < (data.size() / 64); y++) {
302 for (int x = 0; x < sheet_width; x++) { // 128 assumption
303 if (n < data.size()) {
304 // buffer[n] = bitmap_data[(x * sheet_width) + y];
305 buffer[n] = bitmap_data[x][y];
306 n++;
307 }
308 }
309 }
310 return buffer;
311}
312
313uint16_t TileInfoToWord(TileInfo tile_info) {
314 uint16_t result = 0;
315
316 // Copy the id_ value
317 result |= tile_info.id_ & 0x3FF; // ids are 10 bits
318
319 // Set the vertical_mirror_, horizontal_mirror_, and over_ flags
320 result |= (tile_info.vertical_mirror_ ? 1 : 0) << 15;
321 result |= (tile_info.horizontal_mirror_ ? 1 : 0) << 14;
322 result |= (tile_info.over_ ? 1 : 0) << 13;
323
324 // Set the palette_
325 result |= (tile_info.palette_ & 0x07) << 10; // palettes are 3 bits
326
327 return result;
328}
329
330TileInfo WordToTileInfo(uint16_t word) {
331 // Extract the id_ value
332 uint16_t id = word & 0x3FF; // ids are 10 bits
333
334 // Extract the vertical_mirror_, horizontal_mirror_, and over_ flags
335 bool vertical_mirror = (word >> 15) & 0x01;
336 bool horizontal_mirror = (word >> 14) & 0x01;
337 bool over = (word >> 13) & 0x01;
338
339 // Extract the palette_
340 uint8_t palette = (word >> 10) & 0x07; // palettes are 3 bits
341
342 return TileInfo(id, palette, vertical_mirror, horizontal_mirror, over);
343}
344
345uint16_t TileInfoToShort(TileInfo tile_info) {
346 // uint16_t result = 0;
347
348 // Copy the id_ value
349 // result |= tile_info.id_ & 0x3FF; // ids are 10 bits
350
351 // Set the vertical_mirror_, horizontal_mirror_, and over_ flags
352 // result |= (tile_info.vertical_mirror_ ? 1 : 0) << 10;
353 // result |= (tile_info.horizontal_mirror_ ? 1 : 0) << 11;
354 // result |= (tile_info.over_ ? 1 : 0) << 12;
355
356 // Set the palette_
357 // result |= (tile_info.palette_ & 0x07) << 13; // palettes are 3 bits
358
359 uint16_t value = 0;
360 // vhopppcc cccccccc
361 if (tile_info.over_) {
362 value |= TilePriorityBit;
363 }
364 if (tile_info.horizontal_mirror_) {
365 value |= TileHFlipBit;
366 }
367 if (tile_info.vertical_mirror_) {
368 value |= TileVFlipBit;
369 }
370 value |= (uint16_t)((tile_info.palette_ << 10) & 0x1C00);
371 value |= (uint16_t)(tile_info.id_ & TileNameMask);
372
373 return value;
374}
375
376TileInfo GetTilesInfo(uint16_t tile) {
377 // vhopppcc cccccccc
378 uint16_t tid = (uint16_t)(tile & TileNameMask);
379 uint8_t p = (uint8_t)((tile >> 10) & 0x07);
380
381 bool o = ((tile & TilePriorityBit) == TilePriorityBit);
382 bool h = ((tile & TileHFlipBit) == TileHFlipBit);
383 bool v = ((tile & TileVFlipBit) == TileVFlipBit);
384
385 return TileInfo(tid, p, v, h, o);
386}
387
388void CopyTile8bpp16(int x, int y, int tile, std::vector<uint8_t>& bitmap,
389 std::vector<uint8_t>& blockset) {
390 int src_pos =
391 ((tile - ((tile / 0x08) * 0x08)) * 0x10) + ((tile / 0x08) * 2048);
392 int dest_pos = (x + (y * 0x200));
393 for (int yy = 0; yy < 0x10; yy++) {
394 for (int xx = 0; xx < 0x10; xx++) {
395 bitmap[dest_pos + xx + (yy * 0x200)] =
396 blockset[src_pos + xx + (yy * 0x80)];
397 }
398 }
399}
400
401} // namespace gfx
402
403} // namespace yaze
SNES 16-bit tile metadata container.
Definition snes_tile.h:49
Contains classes for handling graphical data.
Definition bitmap.cc:16
constexpr uint16_t TileNameMask
Definition snes_tile.cc:23
constexpr uint16_t TileVFlipBit
Definition snes_tile.cc:20
void CopyTile8bpp16(int x, int y, int tile, std::vector< uint8_t > &bitmap, std::vector< uint8_t > &blockset)
Definition snes_tile.cc:388
uint16_t TileInfoToWord(TileInfo tile_info)
Definition snes_tile.cc:313
uint16_t TileInfoToShort(TileInfo tile_info)
Definition snes_tile.cc:345
std::vector< uint8_t > PackBppTile(const snes_tile8 &tile, const uint32_t bpp)
Definition snes_tile.cc:82
std::vector< uint8_t > Bpp8SnesToIndexed(std::vector< uint8_t > data, uint64_t bpp)
Definition snes_tile.cc:211
std::vector< uint8_t > ConvertBpp(const std::vector< uint8_t > &tiles, uint32_t from_bpp, uint32_t to_bpp)
Definition snes_tile.cc:129
constexpr uint16_t TilePriorityBit
Definition snes_tile.cc:14
TileInfo GetTilesInfo(uint16_t tile)
Definition snes_tile.cc:376
constexpr uint8_t kGraphicsBitmap[8]
Definition snes_tile.h:19
TileInfo WordToTileInfo(uint16_t word)
Definition snes_tile.cc:330
snes_tile8 UnpackBppTile(const std::vector< uint8_t > &data, const uint32_t offset, const uint32_t bpp)
Definition snes_tile.cc:25
std::vector< uint8_t > Convert3bppTo4bpp(const std::vector< uint8_t > &tiles)
Definition snes_tile.cc:143
constexpr uint16_t TileHFlipBit
Definition snes_tile.cc:17
std::vector< uint8_t > Convert4bppTo3bpp(const std::vector< uint8_t > &tiles)
Definition snes_tile.cc:147
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp, int num_sheets)
Definition snes_tile.cc:151
Main namespace for the application.
Definition controller.cc:18
uint8_t data[64]
Definition snes.h:32