From c10f43a9481c5ae5d892f782ee846f819c632cd7 Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 17 Aug 2023 20:31:22 -0400 Subject: [PATCH] Add UnpackBppTile and PackBppTile --- src/app/gfx/snes_tile.cc | 122 +++++++++++++++++++++++++++++++++++++++ src/app/gfx/snes_tile.h | 16 ++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/src/app/gfx/snes_tile.cc b/src/app/gfx/snes_tile.cc index b3b9fbf6..2c408cc7 100644 --- a/src/app/gfx/snes_tile.cc +++ b/src/app/gfx/snes_tile.cc @@ -9,6 +9,128 @@ namespace yaze { namespace app { namespace gfx { +tile8 UnpackBppTile(const Bytes& data, const uint32_t offset, + const uint32_t bpp) { + tile8 tile; + assert(bpp >= 1 && bpp <= 8); + unsigned int bpp_pos[8]; // More for conveniance and readibility + for (int col = 0; col < 8; col++) { + for (int row = 0; row < 8; row++) { + if (bpp == 1) { + tile.data[col * 8 + row] = (data[offset + col] >> (7 - row)) & 0x01; + continue; + } + /* SNES bpp format interlace each byte of the first 2 bitplanes. + * | byte 1 of first bitplane | byte 1 of second bitplane | + * | byte 2 of first bitplane | byte 2 of second bitplane | .. + */ + bpp_pos[0] = offset + col * 2; + bpp_pos[1] = offset + col * 2 + 1; + char mask = 1 << (7 - row); + tile.data[col * 8 + row] = (data[bpp_pos[0]] & mask) == mask; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[1]] & mask) == mask) + << 1; + if (bpp == 3) { + // When we have 3 bitplanes, the bytes for the third bitplane are after + // the 16 bytes of the 2 bitplanes. + bpp_pos[2] = offset + 16 + col; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[2]] & mask) == mask) + << 2; + } + if (bpp >= 4) { + // For 4 bitplanes, the 2 added bitplanes are interlaced like the first + // two. + bpp_pos[2] = offset + 16 + col * 2; + bpp_pos[3] = offset + 16 + col * 2 + 1; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[2]] & mask) == mask) + << 2; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[3]] & mask) == mask) + << 3; + } + if (bpp == 8) { + bpp_pos[4] = offset + 32 + col * 2; + bpp_pos[5] = offset + 32 + col * 2 + 1; + bpp_pos[6] = offset + 48 + col * 2; + bpp_pos[7] = offset + 48 + col * 2 + 1; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[4]] & mask) == mask) + << 4; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[5]] & mask) == mask) + << 5; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[6]] & mask) == mask) + << 6; + tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[7]] & mask) == mask) + << 7; + } + } + } + return tile; +} + +Bytes PackBppTile(const tile8& tile, const uint32_t bpp) { + // Allocate memory for output data + std::vector output(bpp * 8, 0); // initialized with 0 + unsigned maxcolor = 2 << bpp; + + // Iterate over all columns and rows of the tile + for (unsigned int col = 0; col < 8; col++) { + for (unsigned int row = 0; row < 8; row++) { + uchar color = tile.data[col * 8 + row]; + if (color > maxcolor) throw std::runtime_error("Invalid color value."); + + // 1bpp format + if (bpp == 1) output[col] += (uchar)((color & 1) << (7 - row)); + + // 2bpp format + if (bpp >= 2) { + output[col * 2] += (uchar)((color & 1) << (7 - row)); + output[col * 2 + 1] += (uchar)((uchar)((color & 2) == 2) << (7 - row)); + } + + // 3bpp format + if (bpp == 3) + output[16 + col] += (uchar)(((color & 4) == 4) << (7 - row)); + + // 4bpp format + if (bpp >= 4) { + output[16 + col * 2] += (uchar)(((color & 4) == 4) << (7 - row)); + output[16 + col * 2 + 1] += (uchar)(((color & 8) == 8) << (7 - row)); + } + + // 8bpp format + if (bpp == 8) { + output[32 + col * 2] += (uchar)(((color & 16) == 16) << (7 - row)); + output[32 + col * 2 + 1] += (uchar)(((color & 32) == 32) << (7 - row)); + output[48 + col * 2] += (uchar)(((color & 64) == 64) << (7 - row)); + output[48 + col * 2 + 1] += + (uchar)(((color & 128) == 128) << (7 - row)); + } + } + } + return output; +} + +std::vector ConvertBpp(const std::vector& tiles, + uint32_t from_bpp, uint32_t to_bpp) { + unsigned int nb_tile = tiles.size() / (from_bpp * 8); + std::vector converted(nb_tile * to_bpp * 8); + + for (unsigned int i = 0; i < nb_tile; i++) { + tile8 tile = UnpackBppTile(tiles, i * from_bpp * 8, from_bpp); + std::vector packed_tile = PackBppTile(tile, to_bpp); + std::memcpy(converted.data() + i * to_bpp * 8, packed_tile.data(), + to_bpp * 8); + } + return converted; +} + +std::vector Convert3bppTo4bpp(const std::vector& tiles) { + return ConvertBpp(tiles, 3, 4); +} + +std::vector Convert4bppTo3bpp(const std::vector& tiles) { + return ConvertBpp(tiles, 4, 3); +} + Bytes SnesTo8bppSheet(Bytes sheet, int bpp) { int xx = 0; // positions where we are at on the sheet int yy = 0; diff --git a/src/app/gfx/snes_tile.h b/src/app/gfx/snes_tile.h index 223e4441..92cceb65 100644 --- a/src/app/gfx/snes_tile.h +++ b/src/app/gfx/snes_tile.h @@ -2,6 +2,7 @@ #define YAZE_APP_GFX_SNES_TILE_H #include +#include #include #include "app/core/constants.h" @@ -17,12 +18,23 @@ Bytes SnesTo8bppSheet(Bytes sheet, int bpp); Bytes BPP8SNESToIndexed(Bytes data, uint64_t bpp = 0); struct tile8 { - unsigned int id; + uint32_t id; char data[64]; - unsigned int palette_id; + uint32_t palette_id; }; using tile8 = struct tile8; +tile8 UnpackBppTile(const Bytes& data, const uint32_t offset, + const uint32_t bpp); + +Bytes PackBppTile(const tile8& tile, const uint32_t bpp); + +std::vector ConvertBpp(const std::vector& tiles, + uint32_t from_bpp, uint32_t to_bpp); + +std::vector Convert3bppTo4bpp(const std::vector& tiles); +std::vector Convert4bppTo3bpp(const std::vector& tiles); + // vhopppcc cccccccc // [0, 1] // [2, 3]