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