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