backend-infra-engineer: Pre-0.2.2 2024 Q1 snapshot

This commit is contained in:
scawful
2024-02-09 21:44:12 -05:00
parent d94b7a3e81
commit 546093360f
85 changed files with 8868 additions and 3263 deletions

View File

@@ -30,6 +30,24 @@ void PngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
p->insert(p->end(), data, data + length);
}
void PngReadCallback(png_structp png_ptr, png_bytep outBytes,
png_size_t byteCountToRead) {
png_voidp io_ptr = png_get_io_ptr(png_ptr);
if (!io_ptr) return;
std::vector<uint8_t> *png_data =
reinterpret_cast<std::vector<uint8_t> *>(io_ptr);
static size_t pos = 0; // Position to read from
if (pos + byteCountToRead <= png_data->size()) {
memcpy(outBytes, png_data->data() + pos, byteCountToRead);
pos += byteCountToRead;
} else {
png_error(png_ptr, "Read error in PngReadCallback");
}
}
} // namespace
bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector<uint8_t> &buffer) {
png_structp png_ptr = png_create_write_struct("1.6.40", NULL, NULL, NULL);
if (!png_ptr) {
@@ -72,6 +90,10 @@ bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector<uint8_t> &buffer) {
free(pal_ptr);
}
if (surface->format->Amask) { // Check for alpha channel
colortype |= PNG_COLOR_MASK_ALPHA;
}
auto depth = surface->format->BitsPerPixel;
// Set image attributes.
@@ -98,18 +120,6 @@ bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector<uint8_t> &buffer) {
return true;
}
void PngReadCallback(png_structp png_ptr, png_bytep outBytes,
png_size_t byteCountToRead) {
png_voidp io_ptr = png_get_io_ptr(png_ptr);
if (!io_ptr) return;
std::vector<uint8_t> *png_data =
reinterpret_cast<std::vector<uint8_t> *>(io_ptr);
size_t pos = png_data->size() - byteCountToRead;
memcpy(outBytes, png_data->data() + pos, byteCountToRead);
png_data->resize(pos); // Reduce the buffer size
}
void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
SDL_Surface **outSurface) {
std::vector<uint8_t> data(png_data);
@@ -140,59 +150,38 @@ void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
png_byte color_type = png_get_color_type(png_ptr, info_ptr);
png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
// Set up transformations, e.g., strip 16-bit PNGs down to 8-bit, expand
// palettes, etc.
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
}
// PNG files pack pixels, expand them
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_ptr);
}
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
}
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_gray_to_rgb(png_ptr);
}
// Apply necessary transformations...
// (Same as in your existing code)
// Update info structure with transformations
png_read_update_info(png_ptr, info_ptr);
// Read the file
std::vector<png_bytep> row_pointers(height);
std::vector<uint8_t> raw_data(width * height *
4); // Assuming 4 bytes per pixel (RGBA)
std::vector<png_bytep> row_pointers(height);
for (size_t y = 0; y < height; y++) {
row_pointers[y] = &raw_data[y * width * 4];
row_pointers[y] = raw_data.data() + y * width * 4;
}
png_read_image(png_ptr, row_pointers.data());
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
// Create SDL_Surface from raw pixel data
*outSurface = SDL_CreateRGBSurfaceWithFormatFrom(
raw_data.data(), width, height, 32, width * 4, SDL_PIXELFORMAT_RGBA32);
// Create an SDL_Surface
*outSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32,
SDL_PIXELFORMAT_RGBA32);
if (*outSurface == nullptr) {
SDL_Log("SDL_CreateRGBSurfaceWithFormatFrom failed: %s\n", SDL_GetError());
} else {
SDL_Log("Successfully created SDL_Surface from PNG data");
SDL_Log("SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
return;
}
// Copy the raw data into the SDL_Surface
SDL_LockSurface(*outSurface);
memcpy((*outSurface)->pixels, raw_data.data(), raw_data.size());
SDL_UnlockSurface(*outSurface);
SDL_Log("Successfully created SDL_Surface from PNG data");
}
} // namespace
Bitmap::Bitmap(int width, int height, int depth, int data_size) {
Create(width, height, depth, data_size);
@@ -267,7 +256,7 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) {
SDL_UnlockTexture(texture_.get());
}
void Bitmap::UpdateTexture(SDL_Renderer *renderer) {
void Bitmap::UpdateTexture(SDL_Renderer *renderer, bool use_sdl_update) {
SDL_Surface *converted_surface =
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0);
if (converted_surface) {
@@ -282,8 +271,17 @@ void Bitmap::UpdateTexture(SDL_Renderer *renderer) {
SDL_LockTexture(texture_.get(), nullptr, (void **)&texture_pixels,
&converted_surface_->pitch);
memcpy(texture_pixels, converted_surface_->pixels,
converted_surface_->h * converted_surface_->pitch);
try {
if (use_sdl_update) {
SDL_UpdateTexture(texture_.get(), nullptr, converted_surface_->pixels,
converted_surface_->pitch);
} else {
memcpy(texture_pixels, converted_surface_->pixels,
converted_surface_->h * converted_surface_->pitch);
}
} catch (const std::exception &e) {
SDL_Log("Exception: %s\n", e.what());
}
SDL_UnlockTexture(texture_.get());
}
@@ -327,33 +325,54 @@ void Bitmap::LoadFromPngData(const std::vector<uint8_t> &png_data, int width,
}
// Convert SNESPalette to SDL_Palette for surface.
void Bitmap::ApplyPalette(const SNESPalette &palette) {
void Bitmap::ApplyPalette(const SnesPalette &palette) {
palette_ = palette;
SDL_UnlockSurface(surface_.get());
for (int i = 0; i < palette.size(); ++i) {
if (palette.GetColor(i).IsTransparent()) {
if (palette.GetColor(i).is_transparent()) {
surface_->format->palette->colors[i].r = 0;
surface_->format->palette->colors[i].g = 0;
surface_->format->palette->colors[i].b = 0;
surface_->format->palette->colors[i].a = 0;
} else {
surface_->format->palette->colors[i].r = palette.GetColor(i).GetRGB().x;
surface_->format->palette->colors[i].g = palette.GetColor(i).GetRGB().y;
surface_->format->palette->colors[i].b = palette.GetColor(i).GetRGB().z;
surface_->format->palette->colors[i].a = palette.GetColor(i).GetRGB().w;
surface_->format->palette->colors[i].r = palette.GetColor(i).rgb().x;
surface_->format->palette->colors[i].g = palette.GetColor(i).rgb().y;
surface_->format->palette->colors[i].b = palette.GetColor(i).rgb().z;
surface_->format->palette->colors[i].a = palette.GetColor(i).rgb().w;
}
}
SDL_LockSurface(surface_.get());
}
void Bitmap::ApplyPaletteWithTransparent(const SNESPalette &palette,
int index) {
void Bitmap::ApplyPaletteFromPaletteGroup(const SnesPalette &palette,
int palette_id) {
auto start_index = palette_id * 8;
palette_ = palette.sub_palette(start_index, start_index + 8);
SDL_UnlockSurface(surface_.get());
for (int i = 0; i < palette_.size(); ++i) {
if (palette_.GetColor(i).is_transparent()) {
surface_->format->palette->colors[i].r = 0;
surface_->format->palette->colors[i].g = 0;
surface_->format->palette->colors[i].b = 0;
surface_->format->palette->colors[i].a = 0;
} else {
surface_->format->palette->colors[i].r = palette_.GetColor(i).rgb().x;
surface_->format->palette->colors[i].g = palette_.GetColor(i).rgb().y;
surface_->format->palette->colors[i].b = palette_.GetColor(i).rgb().z;
surface_->format->palette->colors[i].a = palette_.GetColor(i).rgb().w;
}
}
SDL_LockSurface(surface_.get());
}
void Bitmap::ApplyPaletteWithTransparent(const SnesPalette &palette, int index,
int length) {
auto start_index = index * 7;
palette_ = palette.sub_palette(start_index, start_index + 7);
std::vector<ImVec4> colors;
colors.push_back(ImVec4(0, 0, 0, 0));
for (int i = start_index; i < start_index + 7; ++i) {
colors.push_back(palette.GetColor(i).GetRGB());
colors.push_back(palette.GetColor(i).rgb());
}
SDL_UnlockSurface(surface_.get());

View File

@@ -17,6 +17,9 @@ namespace yaze {
namespace app {
namespace gfx {
bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector<uint8_t> &buffer);
void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
SDL_Surface **outSurface);
class Bitmap {
public:
Bitmap() = default;
@@ -36,7 +39,7 @@ class Bitmap {
void CreateTexture(std::shared_ptr<SDL_Renderer> renderer);
void UpdateTexture(std::shared_ptr<SDL_Renderer> renderer);
void CreateTexture(SDL_Renderer *renderer);
void UpdateTexture(SDL_Renderer *renderer);
void UpdateTexture(SDL_Renderer *renderer, bool use_sdl_update = false);
void SaveSurfaceToFile(std::string_view filename);
void SetSurface(SDL_Surface *surface);
@@ -44,9 +47,11 @@ class Bitmap {
void LoadFromPngData(const std::vector<uint8_t> &png_data, int width,
int height);
void ApplyPalette(const SNESPalette &palette);
void ApplyPaletteWithTransparent(const SNESPalette &palette, int index);
void ApplyPalette(const SnesPalette &palette);
void ApplyPaletteWithTransparent(const SnesPalette &palette, int index,
int length = 7);
void ApplyPalette(const std::vector<SDL_Color> &palette);
void ApplyPaletteFromPaletteGroup(const SnesPalette &palette, int palette_id);
void WriteToPixel(int position, uchar value) {
if (pixel_data_ == nullptr) {
@@ -67,13 +72,13 @@ class Bitmap {
void Get8x8Tile(int tile_index, int x, int y, std::vector<uint8_t> &tile_data,
int &tile_data_offset) {
int tile_offset = tile_index * 64;
int tile_x = x * 8;
int tile_y = y * 8;
int tile_offset = tile_index * (width_ * height_);
int tile_x = (x * 8) % width_;
int tile_y = (y * 8) % height_;
for (int i = 0; i < 8; i++) {
int row_offset = tile_offset + (i * 8);
int row_offset = tile_offset + ((tile_y + i) * width_);
for (int j = 0; j < 8; j++) {
int pixel_offset = row_offset + j;
int pixel_offset = row_offset + (tile_x + j);
int pixel_value = data_[pixel_offset];
tile_data[tile_data_offset] = pixel_value;
tile_data_offset++;
@@ -81,6 +86,41 @@ class Bitmap {
}
}
void Get16x16Tile(int tile_index, int x, int y,
std::vector<uint8_t> &tile_data, int &tile_data_offset) {
int tile_offset = tile_index * (width_ * height_);
int tile_x = x * 16;
int tile_y = y * 16;
for (int i = 0; i < 16; i++) {
int row_offset = tile_offset + ((i / 8) * (width_ * 8));
for (int j = 0; j < 16; j++) {
int pixel_offset =
row_offset + ((j / 8) * 8) + ((i % 8) * width_) + (j % 8);
int pixel_value = data_[pixel_offset];
tile_data[tile_data_offset] = pixel_value;
tile_data_offset++;
}
}
}
void Get16x16Tile(int tile_x, int tile_y, std::vector<uint8_t> &tile_data,
int &tile_data_offset) {
// Assuming 'width_' and 'height_' are the dimensions of the bitmap
// and 'data_' is the bitmap data.
for (int ty = 0; ty < 16; ty++) {
for (int tx = 0; tx < 16; tx++) {
// Calculate the pixel position in the bitmap
int pixel_x = tile_x + tx;
int pixel_y = tile_y + ty;
int pixel_offset = pixel_y * width_ + pixel_x;
int pixel_value = data_[pixel_offset];
// Store the pixel value in the tile data
tile_data[tile_data_offset++] = pixel_value;
}
}
}
void WriteColor(int position, const ImVec4 &color) {
// Convert ImVec4 (RGBA) to SDL_Color (RGBA)
SDL_Color sdl_color;
@@ -141,6 +181,8 @@ class Bitmap {
auto mutable_pixel_data() { return pixel_data_; }
auto surface() const { return surface_.get(); }
auto mutable_surface() { return surface_.get(); }
auto converted_surface() const { return converted_surface_.get(); }
auto mutable_converted_surface() { return converted_surface_.get(); }
void set_data(const Bytes &data) { data_ = data; }
auto vector() const { return data_; }
@@ -148,8 +190,8 @@ class Bitmap {
auto texture() const { return texture_.get(); }
auto modified() const { return modified_; }
void set_modified(bool modified) { modified_ = modified; }
auto IsActive() const { return active_; }
auto SetActive(bool active) { active_ = active; }
auto is_active() const { return active_; }
auto set_active(bool active) { active_ = active; }
private:
struct SDL_Texture_Deleter {
@@ -186,7 +228,7 @@ class Bitmap {
std::vector<uint8_t> png_data_;
gfx::SNESPalette palette_;
gfx::SnesPalette palette_;
std::shared_ptr<SDL_Texture> texture_ = nullptr;
std::shared_ptr<SDL_Surface> surface_ = nullptr;
std::shared_ptr<SDL_Surface> converted_surface_ = nullptr;
@@ -204,23 +246,24 @@ class BitmapManager {
std::make_shared<gfx::Bitmap>(width, height, depth, data);
}
std::shared_ptr<gfx::Bitmap> const &CopyBitmap(const gfx::Bitmap &bitmap,
int id) {
auto new_bitmap = std::make_shared<gfx::Bitmap>(
bitmap.width(), bitmap.height(), bitmap.depth(), bitmap.vector());
bitmap_cache_[id] = new_bitmap;
return new_bitmap;
}
std::shared_ptr<gfx::Bitmap> const &operator[](int id) {
auto it = bitmap_cache_.find(id);
if (it != bitmap_cache_.end()) {
return it->second;
}
return nullptr;
throw std::runtime_error(
absl::StrCat("Bitmap with id ", id, " not found."));
}
std::shared_ptr<gfx::Bitmap> const &shared_bitmap(int id) {
auto it = bitmap_cache_.find(id);
if (it != bitmap_cache_.end()) {
return it->second;
}
throw std::runtime_error(
absl::StrCat("Bitmap with id ", id, " not found."));
}
auto mutable_bitmap(int id) { return bitmap_cache_[id]; }
void clear_cache() { bitmap_cache_.clear(); }
using value_type = std::pair<const int, std::shared_ptr<gfx::Bitmap>>;
using iterator =
@@ -234,16 +277,6 @@ class BitmapManager {
const_iterator end() const noexcept { return bitmap_cache_.end(); }
const_iterator cbegin() const noexcept { return bitmap_cache_.cbegin(); }
const_iterator cend() const noexcept { return bitmap_cache_.cend(); }
std::shared_ptr<gfx::Bitmap> const &GetBitmap(int id) {
auto it = bitmap_cache_.find(id);
if (it != bitmap_cache_.end()) {
return it->second;
}
return nullptr; // or handle the error accordingly
}
void ClearCache() { bitmap_cache_.clear(); }
};
} // namespace gfx

View File

@@ -588,6 +588,286 @@ absl::StatusOr<Bytes> CompressV2(const uchar* data, const int start,
return CreateCompressionString(compressed_chain_start->next, mode);
}
// Hyrule Magic
uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size,
int const flag) {
unsigned char* b2 =
(unsigned char*)malloc(0x1000); // allocate a 2^12 sized buffer
int i, j, k, l, m = 0, n, o = 0, bd = 0, p, q = 0, r;
for (i = 0; i < oldsize;) {
l = src[i]; // grab a char from the buffer.
k = 0;
r = !!q; // r = the same logical value (0 or 1) as q, but not the same
// value necesarily.
for (j = 0; j < i - 1; j++) {
if (src[j] == l) {
m = oldsize - j;
for (n = 0; n < m; n++)
if (src[n + j] != src[n + i]) break;
if (n > k) k = n, o = j;
}
}
for (n = i + 1; n < oldsize; n++) {
if (src[n] != l) {
// look for chars identical to the first one.
// stop if we can't find one.
// n will reach i+k+1 for some k >= 0.
break;
}
}
n -= i; // offset back by i. i.e. n = k+1 as above.
if (n > 1 + r)
p = 1;
else {
m = src[i + 1];
for (n = i + 2; n < oldsize; n++) {
if (src[n] != l) break;
n++;
if (src[n] != m) break;
}
n -= i;
if (n > 2 + r)
p = 2;
else {
m = oldsize - i;
for (n = 1; n < m; n++)
if (src[i + n] != l + n) break;
if (n > 1 + r)
p = 3;
else
p = 0;
}
}
if (k > 3 + r && k > n + (p & 1)) p = 4, n = k;
if (!p)
q++, i++;
else {
if (q) {
q--;
if (q > 31) {
b2[bd++] = (unsigned char)(224 + (q >> 8));
}
b2[bd++] = (unsigned char)q;
q++;
memcpy(b2 + bd, src + i - q, q);
bd += q;
q = 0;
}
i += n;
n--;
if (n > 31) {
b2[bd++] = (unsigned char)(224 + (n >> 8) + (p << 2));
b2[bd++] = (unsigned char)n;
} else
b2[bd++] = (unsigned char)((p << 5) + n);
switch (p) {
case 1:
case 3:
b2[bd++] = (unsigned char)l;
break;
case 2:
b2[bd++] = (unsigned char)l;
b2[bd++] = (unsigned char)m;
break;
case 4:
if (flag) {
b2[bd++] = (unsigned char)(o >> 8);
b2[bd++] = (unsigned char)o;
} else {
b2[bd++] = (unsigned char)o;
b2[bd++] = (unsigned char)(o >> 8);
}
}
continue;
}
}
if (q) {
q--;
if (q > 31) {
b2[bd++] = (unsigned char)(224 + (q >> 8));
}
b2[bd++] = (unsigned char)q;
q++;
memcpy(b2 + bd, src + i - q, q);
bd += q;
}
b2[bd++] = 255;
b2 = (unsigned char*)realloc(b2, bd);
*size = bd;
return b2;
}
uint8_t* Uncompress(uint8_t const* src, int* const size,
int const p_big_endian) {
unsigned char* b2 = (unsigned char*)malloc(1024);
int bd = 0, bs = 1024;
unsigned char a;
unsigned char b;
unsigned short c, d;
for (;;) {
// retrieve a uchar from the buffer.
a = *(src++);
// end the decompression routine if we encounter 0xff.
if (a == 0xff) break;
// examine the top 3 bits of a.
b = (a >> 5);
if (b == 7) // i.e. 0b 111
{
// get bits 0b 0001 1100
b = ((a >> 2) & 7);
// get bits 0b 0000 0011, multiply by 256, OR with the next byte.
c = ((a & 0x0003) << 8);
c |= *(src++);
} else
// or get bits 0b 0001 1111
c = (uint16_t)(a & 31);
c++;
if ((bd + c) > (bs - 512)) {
// need to increase the buffer size.
bs += 1024;
b2 = (uint8_t*)realloc(b2, bs);
}
// 7 was handled, here we handle other decompression codes.
switch (b) {
case 0: // 0b 000
// raw copy
// copy info from the src buffer to our new buffer,
// at offset bd (which we'll be increasing;
memcpy(b2 + bd, src, c);
// increment the src pointer accordingly.
src += c;
bd += c;
break;
case 1: // 0b 001
// rle copy
// make c duplicates of one byte, inc the src pointer.
memset(b2 + bd, *(src++), c);
// increase the b2 offset.
bd += c;
break;
case 2: // 0b 010
// rle 16-bit alternating copy
d = core::ldle16b(src);
src += 2;
while (c > 1) {
// copy that 16-bit number c/2 times into the b2 buffer.
core::stle16b(b2 + bd, d);
bd += 2;
c -= 2; // hence c/2
}
if (c) // if there's a remainder of c/2, this handles it.
b2[bd++] = (char)d;
break;
case 3: // 0b 011
// incrementing copy
// get the current src byte.
a = *(src++);
while (c--) {
// increment that byte and copy to b2 in c iterations.
// e.g. a = 4, b2 will have 4,5,6,7,8... written to it.
b2[bd++] = a++;
}
break;
default: // 0b 100, 101, 110
// lz copy
if (p_big_endian) {
d = (*src << 8) + src[1];
} else {
d = core::ldle16b(src);
}
while (c--) {
// copy from a different location in the buffer.
b2[bd++] = b2[d++];
}
src += 2;
}
}
b2 = (unsigned char*)realloc(b2, bd);
if (size) (*size) = bd;
// return the unsigned char* buffer b2, which contains the uncompressed data.
return b2;
}
absl::StatusOr<Bytes> CompressGraphics(const uchar* data, const int pos,
const int length) {
return CompressV2(data, pos, length, kNintendoMode2);
@@ -598,6 +878,11 @@ absl::StatusOr<Bytes> CompressOverworld(const uchar* data, const int pos,
return CompressV2(data, pos, length, kNintendoMode1);
}
absl::StatusOr<Bytes> CompressOverworld(const std::vector<uint8_t> data,
const int pos, const int length) {
return CompressV3(data, pos, length, kNintendoMode1);
}
// ============================================================================
// Compression V3
@@ -1019,7 +1304,7 @@ void FinalizeCompression(CompressionContext& context) {
<< context.compressed_data.size());
}
absl::StatusOr<Bytes> CompressV3(const std::vector<uint8_t> data,
absl::StatusOr<Bytes> CompressV3(const std::vector<uint8_t>& data,
const int start, const int length, int mode,
bool check) {
if (length == 0) {

View File

@@ -15,8 +15,29 @@ namespace yaze {
namespace app {
namespace gfx {
const int D_NINTENDO_C_MODE1 = 0;
const int D_NINTENDO_C_MODE2 = 1;
const int D_CMD_COPY = 0;
const int D_CMD_BYTE_REPEAT = 1;
const int D_CMD_WORD_REPEAT = 2;
const int D_CMD_BYTE_INC = 3;
const int D_CMD_COPY_EXISTING = 4;
const int D_MAX_NORMAL_LENGTH = 32;
const int D_MAX_LENGTH = 1024;
const int INITIAL_ALLOC_SIZE = 1024;
namespace lc_lz2 {
absl::StatusOr<Bytes> ZS_Compress(const std::vector<uint8_t>& data,
const int start, const int length,
int mode = 1, bool check = false);
absl::StatusOr<Bytes> ZS_CompressOverworld(const std::vector<uint8_t> data,
const int pos, const int length);
constexpr int kCommandDirectCopy = 0;
constexpr int kCommandByteFill = 1;
constexpr int kCommandWordFill = 2;
@@ -128,6 +149,8 @@ absl::StatusOr<Bytes> CompressGraphics(const uchar* data, const int pos,
const int length);
absl::StatusOr<Bytes> CompressOverworld(const uchar* data, const int pos,
const int length);
absl::StatusOr<Bytes> CompressOverworld(const std::vector<uint8_t> data,
const int pos, const int length);
absl::StatusOr<CompressionPiecePointer> SplitCompressionPiece(
CompressionPiecePointer& piece, int mode);
@@ -185,10 +208,17 @@ absl::StatusOr<CompressionPiece> SplitCompressionPieceV3(
CompressionPiece& piece, int mode);
void FinalizeCompression(CompressionContext& context);
absl::StatusOr<Bytes> CompressV3(const std::vector<uint8_t> data,
absl::StatusOr<Bytes> CompressV3(const std::vector<uint8_t>& data,
const int start, const int length,
int mode = 1, bool check = false);
// Hyrule Magic
uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size,
int const flag);
uint8_t* Uncompress(uint8_t const* src, int* const size,
int const p_big_endian);
// Decompression
std::string SetBuffer(const std::vector<uint8_t>& data, int src_pos,

104
src/app/gfx/snes_color.cc Normal file
View File

@@ -0,0 +1,104 @@
#include "app/gfx/snes_color.h"
#include <imgui/imgui.h>
#include <cstdint>
#include <vector>
namespace yaze {
namespace app {
namespace gfx {
constexpr uint16_t SNES_RED_MASK = 32;
constexpr uint16_t SNES_GREEN_MASK = 32;
constexpr uint16_t SNES_BLUE_MASK = 32;
constexpr uint16_t SNES_GREEN_SHIFT = 32;
constexpr uint16_t SNES_BLUE_SHIFT = 1024;
snes_color ConvertSNEStoRGB(uint16_t color_snes) {
snes_color result;
result.red = (color_snes % SNES_RED_MASK) * 8;
result.green = ((color_snes / SNES_GREEN_MASK) % SNES_GREEN_MASK) * 8;
result.blue = ((color_snes / SNES_BLUE_SHIFT) % SNES_BLUE_MASK) * 8;
result.red += result.red / SNES_RED_MASK;
result.green += result.green / SNES_GREEN_MASK;
result.blue += result.blue / SNES_BLUE_MASK;
return result;
}
uint16_t ConvertRGBtoSNES(const snes_color& color) {
uint16_t red = color.red / 8;
uint16_t green = color.green / 8;
uint16_t blue = color.blue / 8;
return (blue * SNES_BLUE_SHIFT) + (green * SNES_GREEN_SHIFT) + red;
}
uint16_t ConvertRGBtoSNES(const ImVec4& color) {
snes_color new_color;
new_color.red = color.x * 255;
new_color.green = color.y * 255;
new_color.blue = color.z * 255;
return ConvertRGBtoSNES(new_color);
}
SnesColor ReadColorFromRom(int offset, const uint8_t* rom) {
short color = (uint16_t)((rom[offset + 1]) << 8) | rom[offset];
snes_color new_color;
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
new_color.blue = ((color >> 10) & 0x1F) * 8;
SnesColor snes_color(new_color);
return snes_color;
}
std::vector<snes_color> Extract(const char* data, unsigned int offset,
unsigned int palette_size) {
std::vector<snes_color> palette(palette_size);
for (unsigned int i = 0; i < palette_size * 2; i += 2) {
uint16_t snes_color = (static_cast<uint8_t>(data[offset + i + 1]) << 8) |
static_cast<uint8_t>(data[offset + i]);
palette[i / 2] = ConvertSNEStoRGB(snes_color);
}
return palette;
}
std::vector<char> Convert(const std::vector<snes_color>& palette) {
std::vector<char> data(palette.size() * 2);
for (unsigned int i = 0; i < palette.size(); i++) {
uint16_t snes_data = ConvertRGBtoSNES(palette[i]);
data[i * 2] = snes_data & 0xFF;
data[i * 2 + 1] = snes_data >> 8;
}
return data;
}
SnesColor GetCgxColor(uint16_t color) {
ImVec4 rgb;
rgb.x = (color & 0x1F) * 8;
rgb.y = ((color & 0x3E0) >> 5) * 8;
rgb.z = ((color & 0x7C00) >> 10) * 8;
SnesColor toret;
toret.set_rgb(rgb);
return toret;
}
std::vector<SnesColor> GetColFileData(uint8_t* data) {
std::vector<SnesColor> colors;
colors.reserve(256);
colors.resize(256);
for (int i = 0; i < 512; i += 2) {
colors[i / 2] = GetCgxColor((uint16_t)((data[i + 1] << 8) + data[i]));
}
return colors;
}
} // namespace gfx
} // namespace app
} // namespace yaze

99
src/app/gfx/snes_color.h Normal file
View File

@@ -0,0 +1,99 @@
#ifndef YAZE_APP_GFX_SNES_COLOR_H_
#define YAZE_APP_GFX_SNES_COLOR_H_
#include <imgui/imgui.h>
#include <cstdint>
#include <vector>
namespace yaze {
namespace app {
namespace gfx {
struct snes_color {
uint16_t red; /**< Red component of the color. */
uint16_t blue; /**< Blue component of the color. */
uint16_t green; /**< Green component of the color. */
};
typedef struct snes_color snes_color;
snes_color ConvertSNEStoRGB(uint16_t snes_color);
uint16_t ConvertRGBtoSNES(const snes_color& color);
uint16_t ConvertRGBtoSNES(const ImVec4& color);
std::vector<snes_color> Extract(const char* data, unsigned int offset,
unsigned int palette_size);
std::vector<char> Convert(const std::vector<snes_color>& palette);
class SnesColor {
public:
SnesColor() : rgb_(0.f, 0.f, 0.f, 0.f), snes_(0) {}
explicit SnesColor(const ImVec4 val) : rgb_(val) {
snes_color color;
color.red = val.x / 255;
color.green = val.y / 255;
color.blue = val.z / 255;
snes_ = ConvertRGBtoSNES(color);
}
explicit SnesColor(const snes_color val)
: rgb_(val.red, val.green, val.blue, 255.f),
snes_(ConvertRGBtoSNES(val)),
rom_color_(val) {}
SnesColor(uint8_t r, uint8_t g, uint8_t b) {
rgb_ = ImVec4(r, g, b, 255.f);
snes_color color;
color.red = r;
color.green = g;
color.blue = b;
snes_ = ConvertRGBtoSNES(color);
rom_color_ = color;
}
ImVec4 rgb() const { return rgb_; }
void set_rgb(const ImVec4 val) {
rgb_.x = val.x / 255;
rgb_.y = val.y / 255;
rgb_.z = val.z / 255;
snes_color color;
color.red = val.x;
color.green = val.y;
color.blue = val.z;
rom_color_ = color;
snes_ = ConvertRGBtoSNES(color);
modified = true;
}
void set_snes(uint16_t val) {
snes_ = val;
snes_color col = ConvertSNEStoRGB(val);
rgb_ = ImVec4(col.red, col.green, col.blue, 0.f);
modified = true;
}
snes_color rom_color() const { return rom_color_; }
uint16_t snes() const { return snes_; }
bool is_modified() const { return modified; }
bool is_transparent() const { return transparent; }
void set_transparent(bool t) { transparent = t; }
void set_modified(bool m) { modified = m; }
private:
ImVec4 rgb_;
uint16_t snes_;
snes_color rom_color_;
bool modified = false;
bool transparent = false;
};
SnesColor ReadColorFromRom(int offset, const uint8_t* rom);
SnesColor GetCgxColor(uint16_t color);
std::vector<SnesColor> GetColFileData(uint8_t* data);
} // namespace gfx
} // namespace app
} // namespace yaze
#endif // YAZE_APP_GFX_SNES_COLOR_H_

View File

@@ -12,14 +12,15 @@
#include "absl/container/flat_hash_map.h" // for flat_hash_map
#include "absl/status/status.h" // for Status
#include "absl/status/statusor.h"
#include "app/core/constants.h"
#include "app/gfx/snes_color.h"
namespace yaze {
namespace app {
namespace gfx {
// Define a hash map to hold the addresses of different palette groups
const absl::flat_hash_map<std::string, uint32_t> paletteGroupAddresses = {
const absl::flat_hash_map<std::string, uint32_t> kPaletteGroupAddressMap = {
{"ow_main", core::overworldPaletteMain},
{"ow_aux", core::overworldPaletteAuxialiary},
{"ow_animated", core::overworldPaletteAnimated},
@@ -37,8 +38,7 @@ const absl::flat_hash_map<std::string, uint32_t> paletteGroupAddresses = {
{"ow_mini_map", core::overworldMiniMapPalettes},
};
// Define a hash map to hold the number of colors in each palette group
const absl::flat_hash_map<std::string, uint32_t> paletteGroupColorCounts = {
const absl::flat_hash_map<std::string, uint32_t> kPaletteGroupColorCounts = {
{"ow_main", 35}, {"ow_aux", 21}, {"ow_animated", 7},
{"hud", 32}, {"global_sprites", 60}, {"armors", 15},
{"swords", 3}, {"shields", 4}, {"sprites_aux1", 7},
@@ -46,200 +46,13 @@ const absl::flat_hash_map<std::string, uint32_t> paletteGroupColorCounts = {
{"grass", 1}, {"3d_object", 8}, {"ow_mini_map", 128},
};
constexpr uint16_t SNES_RED_MASK = 32;
constexpr uint16_t SNES_GREEN_MASK = 32;
constexpr uint16_t SNES_BLUE_MASK = 32;
constexpr uint16_t SNES_GREEN_SHIFT = 32;
constexpr uint16_t SNES_BLUE_SHIFT = 1024;
uint16_t ConvertRGBtoSNES(const snes_color& color) {
uint16_t red = color.red / 8;
uint16_t green = color.green / 8;
uint16_t blue = color.blue / 8;
return (blue * SNES_BLUE_SHIFT) + (green * SNES_GREEN_SHIFT) + red;
}
uint16_t ConvertRGBtoSNES(const ImVec4& color) {
snes_color new_color;
new_color.red = color.x * 255;
new_color.green = color.y * 255;
new_color.blue = color.z * 255;
return ConvertRGBtoSNES(new_color);
}
snes_color ConvertSNEStoRGB(uint16_t color_snes) {
snes_color result;
result.red = (color_snes % SNES_RED_MASK) * 8;
result.green = ((color_snes / SNES_GREEN_MASK) % SNES_GREEN_MASK) * 8;
result.blue = ((color_snes / SNES_BLUE_SHIFT) % SNES_BLUE_MASK) * 8;
result.red += result.red / SNES_RED_MASK;
result.green += result.green / SNES_GREEN_MASK;
result.blue += result.blue / SNES_BLUE_MASK;
return result;
}
std::vector<snes_color> Extract(const char* data, unsigned int offset,
unsigned int palette_size) {
std::vector<snes_color> palette(palette_size);
for (unsigned int i = 0; i < palette_size * 2; i += 2) {
uint16_t snes_color = (static_cast<uint8_t>(data[offset + i + 1]) << 8) |
static_cast<uint8_t>(data[offset + i]);
palette[i / 2] = ConvertSNEStoRGB(snes_color);
}
return palette;
}
std::vector<char> Convert(const std::vector<snes_color>& palette) {
std::vector<char> data(palette.size() * 2);
for (unsigned int i = 0; i < palette.size(); i++) {
uint16_t snes_data = ConvertRGBtoSNES(palette[i]);
data[i * 2] = snes_data & 0xFF;
data[i * 2 + 1] = snes_data >> 8;
}
return data;
}
SNESColor ReadColorFromROM(int offset, const uchar* rom) {
short color = (ushort)((rom[offset + 1]) << 8) | rom[offset];
snes_color new_color;
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
new_color.blue = ((color >> 10) & 0x1F) * 8;
SNESColor snes_color(new_color);
return snes_color;
}
SNESColor GetCgxColor(uint16_t color) {
ImVec4 rgb;
rgb.x = (color & 0x1F) * 8;
rgb.y = ((color & 0x3E0) >> 5) * 8;
rgb.z = ((color & 0x7C00) >> 10) * 8;
SNESColor toret;
toret.SetRGB(rgb);
return toret;
}
std::vector<SNESColor> GetColFileData(uchar* data) {
std::vector<SNESColor> colors;
colors.reserve(256);
colors.resize(256);
for (int i = 0; i < 512; i += 2) {
colors[i / 2] = GetCgxColor((uint16_t)((data[i + 1] << 8) + data[i]));
}
return colors;
}
// ============================================================================
SNESPalette::SNESPalette(uint8_t mSize) : size_(mSize) {
for (unsigned int i = 0; i < mSize; i++) {
SNESColor col;
colors.push_back(col);
}
}
SNESPalette::SNESPalette(char* data) : size_(sizeof(data) / 2) {
assert((sizeof(data) % 4 == 0) && (sizeof(data) <= 32));
for (unsigned i = 0; i < sizeof(data); i += 2) {
SNESColor col;
col.SetSNES(static_cast<uchar>(data[i + 1]) << 8);
col.SetSNES(col.GetSNES() | static_cast<uchar>(data[i]));
snes_color mColor = ConvertSNEStoRGB(col.GetSNES());
col.SetRGB(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f));
colors.push_back(col);
}
}
SNESPalette::SNESPalette(const unsigned char* snes_pal)
: size_(sizeof(snes_pal) / 2) {
assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32));
for (unsigned i = 0; i < sizeof(snes_pal); i += 2) {
SNESColor col;
col.SetSNES(snes_pal[i + 1] << (uint16_t)8);
col.SetSNES(col.GetSNES() | snes_pal[i]);
snes_color mColor = ConvertSNEStoRGB(col.GetSNES());
col.SetRGB(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f));
colors.push_back(col);
}
}
SNESPalette::SNESPalette(const std::vector<ImVec4>& cols) {
for (const auto& each : cols) {
SNESColor scol;
scol.SetRGB(each);
colors.push_back(scol);
}
size_ = cols.size();
}
SNESPalette::SNESPalette(const std::vector<snes_color>& cols) {
for (const auto& each : cols) {
SNESColor scol;
scol.SetSNES(ConvertRGBtoSNES(each));
colors.push_back(scol);
}
size_ = cols.size();
}
SNESPalette::SNESPalette(const std::vector<SNESColor>& cols) {
for (const auto& each : cols) {
colors.push_back(each);
}
size_ = cols.size();
}
SDL_Palette* SNESPalette::GetSDL_Palette() {
auto sdl_palette = std::make_shared<SDL_Palette>();
sdl_palette->ncolors = size_;
auto color = std::vector<SDL_Color>(size_);
for (int i = 0; i < size_; i++) {
color[i].r = (uint8_t)colors[i].GetRGB().x * 100;
color[i].g = (uint8_t)colors[i].GetRGB().y * 100;
color[i].b = (uint8_t)colors[i].GetRGB().z * 100;
color[i].a = 0;
std::cout << "Color " << i << " added (R:" << color[i].r
<< " G:" << color[i].g << " B:" << color[i].b << ")" << std::endl;
}
sdl_palette->colors = color.data();
return sdl_palette.get();
}
SNESPalette ReadPaletteFromROM(int offset, int num_colors, const uchar* rom) {
int color_offset = 0;
std::vector<gfx::SNESColor> colors(num_colors);
while (color_offset < num_colors) {
short color = (ushort)((rom[offset + 1]) << 8) | rom[offset];
gfx::snes_color new_color;
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
new_color.blue = ((color >> 10) & 0x1F) * 8;
colors[color_offset].SetSNES(ConvertRGBtoSNES(new_color));
if (color_offset == 0) {
colors[color_offset].SetTransparent(true);
}
color_offset++;
offset += 2;
}
gfx::SNESPalette palette(colors);
return palette;
}
uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
size_t color_index) {
// Retrieve the base address for the palette group
uint32_t base_address = paletteGroupAddresses.at(group_name);
uint32_t base_address = kPaletteGroupAddressMap.at(group_name);
// Retrieve the number of colors for each palette in the group
uint32_t colors_per_palette = paletteGroupColorCounts.at(group_name);
uint32_t colors_per_palette = kPaletteGroupColorCounts.at(group_name);
// Calculate the address for thes specified color in the ROM
uint32_t address = base_address + (palette_index * colors_per_palette * 2) +
@@ -248,47 +61,145 @@ uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
return address;
}
std::array<float, 4> ToFloatArray(const SNESColor& color) {
// ============================================================================
SnesPalette::SnesPalette(uint8_t mSize) : size_(mSize) {
for (unsigned int i = 0; i < mSize; i++) {
SnesColor col;
colors.push_back(col);
}
size_ = mSize;
}
SnesPalette::SnesPalette(char* data) : size_(sizeof(data) / 2) {
assert((sizeof(data) % 4 == 0) && (sizeof(data) <= 32));
for (unsigned i = 0; i < sizeof(data); i += 2) {
SnesColor col;
col.set_snes(static_cast<uchar>(data[i + 1]) << 8);
col.set_snes(col.snes() | static_cast<uchar>(data[i]));
snes_color mColor = ConvertSNEStoRGB(col.snes());
col.set_rgb(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f));
colors.push_back(col);
}
size_ = sizeof(data) / 2;
}
SnesPalette::SnesPalette(const unsigned char* snes_pal)
: size_(sizeof(snes_pal) / 2) {
assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32));
for (unsigned i = 0; i < sizeof(snes_pal); i += 2) {
SnesColor col;
col.set_snes(snes_pal[i + 1] << (uint16_t)8);
col.set_snes(col.snes() | snes_pal[i]);
snes_color mColor = ConvertSNEStoRGB(col.snes());
col.set_rgb(ImVec4(mColor.red, mColor.green, mColor.blue, 1.f));
colors.push_back(col);
}
size_ = sizeof(snes_pal) / 2;
}
SnesPalette::SnesPalette(const std::vector<ImVec4>& cols) {
for (const auto& each : cols) {
SnesColor scol;
scol.set_rgb(each);
colors.push_back(scol);
}
size_ = cols.size();
}
SnesPalette::SnesPalette(const std::vector<snes_color>& cols) {
for (const auto& each : cols) {
SnesColor scol;
scol.set_snes(ConvertRGBtoSNES(each));
colors.push_back(scol);
}
size_ = cols.size();
}
SnesPalette::SnesPalette(const std::vector<SnesColor>& cols) {
for (const auto& each : cols) {
colors.push_back(each);
}
size_ = cols.size();
}
SDL_Palette* SnesPalette::GetSDL_Palette() {
auto sdl_palette = std::make_shared<SDL_Palette>();
sdl_palette->ncolors = size_;
auto color = std::vector<SDL_Color>(size_);
for (int i = 0; i < size_; i++) {
color[i].r = (uint8_t)colors[i].rgb().x * 100;
color[i].g = (uint8_t)colors[i].rgb().y * 100;
color[i].b = (uint8_t)colors[i].rgb().z * 100;
color[i].a = 0;
std::cout << "Color " << i << " added (R:" << color[i].r
<< " G:" << color[i].g << " B:" << color[i].b << ")" << std::endl;
}
sdl_palette->colors = color.data();
return sdl_palette.get();
}
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uchar* rom) {
int color_offset = 0;
std::vector<gfx::SnesColor> colors(num_colors);
while (color_offset < num_colors) {
short color = (ushort)((rom[offset + 1]) << 8) | rom[offset];
gfx::snes_color new_color;
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
new_color.blue = ((color >> 10) & 0x1F) * 8;
colors[color_offset].set_snes(ConvertRGBtoSNES(new_color));
if (color_offset == 0) {
colors[color_offset].set_transparent(true);
}
color_offset++;
offset += 2;
}
return gfx::SnesPalette(colors);
}
std::array<float, 4> ToFloatArray(const SnesColor& color) {
std::array<float, 4> colorArray;
colorArray[0] = color.GetRGB().x / 255.0f;
colorArray[1] = color.GetRGB().y / 255.0f;
colorArray[2] = color.GetRGB().z / 255.0f;
colorArray[3] = color.GetRGB().w;
colorArray[0] = color.rgb().x / 255.0f;
colorArray[1] = color.rgb().y / 255.0f;
colorArray[2] = color.rgb().z / 255.0f;
colorArray[3] = color.rgb().w;
return colorArray;
}
PaletteGroup::PaletteGroup(uint8_t mSize) : size_(mSize) {}
PaletteGroup CreatePaletteGroupFromColFile(
std::vector<SNESColor>& palette_rows) {
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromColFile(
std::vector<SnesColor>& palette_rows) {
PaletteGroup toret;
for (int i = 0; i < palette_rows.size(); i += 8) {
SNESPalette palette;
SnesPalette palette;
for (int j = 0; j < 8; j++) {
palette.AddColor(palette_rows[i + j].GetRomRGB());
palette.AddColor(palette_rows[i + j].rom_color());
}
toret.AddPalette(palette);
RETURN_IF_ERROR(toret.AddPalette(palette));
}
return toret;
}
// Take a SNESPalette with N many colors and divide it into palettes of 8 colors
// each
PaletteGroup CreatePaletteGroupFromLargePalette(SNESPalette& palette) {
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromLargePalette(
SnesPalette& palette) {
PaletteGroup toret;
std::cout << "Palette size is " << palette.size() << std::endl;
for (int i = 0; i < palette.size(); i += 8) {
SNESPalette new_palette;
SnesPalette new_palette;
if (i + 8 < palette.size()) {
for (int j = 0; j < 8; j++) {
new_palette.AddColor(palette[i + j]);
}
}
toret.AddPalette(new_palette);
RETURN_IF_ERROR(toret.AddPalette(new_palette));
}
return toret;
}

View File

@@ -13,19 +13,14 @@
#include "absl/base/casts.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "app/core/constants.h"
#include "app/gfx/snes_color.h"
namespace yaze {
namespace app {
namespace gfx {
struct snes_color {
uint16_t red; /**< Red component of the color. */
uint16_t blue; /**< Blue component of the color. */
uint16_t green; /**< Green component of the color. */
};
using snes_color = struct snes_color;
struct snes_palette {
uint id; /**< ID of the palette. */
uint size; /**< Size of the palette. */
@@ -33,115 +28,38 @@ struct snes_palette {
};
using snes_palette = struct snes_palette;
uint16_t ConvertRGBtoSNES(const snes_color& color);
uint16_t ConvertRGBtoSNES(const ImVec4& color);
snes_color ConvertSNEStoRGB(uint16_t snes_color);
uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
size_t color_index);
/**
* @brief Extracts a vector of SNES colors from a data buffer.
*
* @param data The data buffer to extract from.
* @param offset The offset in the buffer to start extracting from.
* @param palette_size The size of the palette to extract.
* @return A vector of SNES colors extracted from the buffer.
*/
std::vector<snes_color> Extract(const char* data, unsigned int offset,
unsigned int palette_size);
/**
* @brief Converts a vector of SNES colors to a vector of characters.
*
* @param palette The vector of SNES colors to convert.
* @return A vector of characters representing the converted SNES colors.
*/
std::vector<char> Convert(const std::vector<snes_color>& palette);
struct SNESColor {
SNESColor() : rgb(0.f, 0.f, 0.f, 0.f), snes(0) {}
explicit SNESColor(const ImVec4 val) : rgb(val) {
snes_color color;
color.red = val.x / 255;
color.green = val.y / 255;
color.blue = val.z / 255;
snes = ConvertRGBtoSNES(color);
}
explicit SNESColor(const snes_color val)
: rgb(val.red, val.green, val.blue, 255.f),
snes(ConvertRGBtoSNES(val)),
rom_color(val) {}
ImVec4 GetRGB() const { return rgb; }
void SetRGB(const ImVec4 val) {
rgb.x = val.x / 255;
rgb.y = val.y / 255;
rgb.z = val.z / 255;
snes_color color;
color.red = val.x;
color.green = val.y;
color.blue = val.z;
rom_color = color;
snes = ConvertRGBtoSNES(color);
modified = true;
}
snes_color GetRomRGB() const { return rom_color; }
uint16_t GetSNES() const { return snes; }
void SetSNES(uint16_t val) {
snes = val;
snes_color col = ConvertSNEStoRGB(val);
rgb = ImVec4(col.red, col.green, col.blue, 0.f);
modified = true;
}
bool IsModified() const { return modified; }
bool IsTransparent() const { return transparent; }
void SetTransparent(bool t) { transparent = t; }
void SetModified(bool m) { modified = m; }
private:
ImVec4 rgb;
uint16_t snes;
snes_color rom_color;
bool modified = false;
bool transparent = false;
};
gfx::SNESColor ReadColorFromROM(int offset, const uchar* rom);
SNESColor GetCgxColor(uint16_t color);
std::vector<SNESColor> GetColFileData(uchar* data);
class SNESPalette {
class SnesPalette {
public:
template <typename T>
explicit SNESPalette(const std::vector<T>& data) {
explicit SnesPalette(const std::vector<T>& data) {
for (const auto& item : data) {
colors.push_back(SNESColor(item));
colors.push_back(SnesColor(item));
}
size_ = data.size();
}
SNESPalette() = default;
SnesPalette() = default;
explicit SNESPalette(uint8_t mSize);
explicit SNESPalette(char* snesPal);
explicit SNESPalette(const unsigned char* snes_pal);
explicit SNESPalette(const std::vector<ImVec4>&);
explicit SNESPalette(const std::vector<snes_color>&);
explicit SNESPalette(const std::vector<SNESColor>&);
explicit SnesPalette(uint8_t mSize);
explicit SnesPalette(char* snesPal);
explicit SnesPalette(const unsigned char* snes_pal);
explicit SnesPalette(const std::vector<ImVec4>&);
explicit SnesPalette(const std::vector<snes_color>&);
explicit SnesPalette(const std::vector<SnesColor>&);
SDL_Palette* GetSDL_Palette();
void Create(const std::vector<SNESColor>& cols) {
void Create(const std::vector<SnesColor>& cols) {
for (const auto& each : cols) {
colors.push_back(each);
}
size_ = cols.size();
}
void AddColor(SNESColor color) {
void AddColor(SnesColor color) {
colors.push_back(color);
size_++;
}
@@ -153,11 +71,14 @@ class SNESPalette {
auto GetColor(int i) const {
if (i > size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
std::cout << "SNESPalette: Index out of bounds" << std::endl;
return colors[0];
}
return colors[i];
}
auto mutable_color(int i) { return &colors[i]; }
void Clear() {
colors.clear();
size_ = 0;
@@ -165,14 +86,15 @@ class SNESPalette {
auto size() const { return colors.size(); }
SNESColor& operator[](int i) {
SnesColor& operator[](int i) {
if (i > size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
std::cout << "SNESPalette: Index out of bounds" << std::endl;
return colors[0];
}
return colors[i];
}
void operator()(int i, const SNESColor& color) {
void operator()(int i, const SnesColor& color) {
if (i >= size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
}
@@ -183,12 +105,12 @@ class SNESPalette {
if (i >= size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
}
colors[i].SetRGB(color);
colors[i].SetModified(true);
colors[i].set_rgb(color);
colors[i].set_modified(true);
}
SNESPalette sub_palette(int start, int end) const {
SNESPalette pal;
SnesPalette sub_palette(int start, int end) const {
SnesPalette pal;
for (int i = start; i < end; i++) {
pal.AddColor(colors[i]);
}
@@ -197,26 +119,27 @@ class SNESPalette {
private:
int size_ = 0; /**< The size of the palette. */
std::vector<SNESColor> colors; /**< The colors in the palette. */
std::vector<SnesColor> colors; /**< The colors in the palette. */
};
SNESPalette ReadPaletteFromROM(int offset, int num_colors, const uchar* rom);
uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
size_t color_index);
std::array<float, 4> ToFloatArray(const SNESColor& color);
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t* rom);
std::array<float, 4> ToFloatArray(const SnesColor& color);
struct PaletteGroup {
PaletteGroup() = default;
explicit PaletteGroup(uint8_t mSize);
absl::Status AddPalette(SNESPalette pal) {
auto mutable_palette(int i) { return &palettes[i]; }
absl::Status AddPalette(SnesPalette pal) {
palettes.emplace_back(pal);
size_ = palettes.size();
return absl::OkStatus();
}
absl::Status AddColor(SNESColor color) {
absl::Status AddColor(SnesColor color) {
if (size_ == 0) {
palettes.emplace_back();
}
@@ -231,7 +154,7 @@ struct PaletteGroup {
auto size() const { return palettes.size(); }
SNESPalette operator[](int i) {
SnesPalette operator[](int i) {
if (i > size_) {
std::cout << "PaletteGroup: Index out of bounds" << std::endl;
return palettes[0];
@@ -239,7 +162,7 @@ struct PaletteGroup {
return palettes[i];
}
const SNESPalette& operator[](int i) const {
const SnesPalette& operator[](int i) const {
if (i > size_) {
std::cout << "PaletteGroup: Index out of bounds" << std::endl;
return palettes[0];
@@ -247,7 +170,7 @@ struct PaletteGroup {
return palettes[i];
}
absl::Status operator()(int i, const SNESColor& color) {
absl::Status operator()(int i, const SnesColor& color) {
if (i >= size_) {
return absl::InvalidArgumentError("PaletteGroup: Index out of bounds");
}
@@ -265,12 +188,40 @@ struct PaletteGroup {
private:
int size_ = 0;
std::vector<SNESPalette> palettes;
std::vector<SnesPalette> palettes;
};
PaletteGroup CreatePaletteGroupFromColFile(std::vector<SNESColor>& colors);
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromColFile(
std::vector<SnesColor>& colors);
PaletteGroup CreatePaletteGroupFromLargePalette(SNESPalette& palette);
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromLargePalette(
SnesPalette& palette);
struct Paletteset {
Paletteset() = default;
Paletteset(gfx::SnesPalette main, gfx::SnesPalette animated,
gfx::SnesPalette aux1, gfx::SnesPalette aux2,
gfx::SnesColor background, gfx::SnesPalette hud,
gfx::SnesPalette spr, gfx::SnesPalette spr2, gfx::SnesPalette comp)
: main(main),
animated(animated),
aux1(aux1),
aux2(aux2),
background(background),
hud(hud),
spr(spr),
spr2(spr2),
composite(comp) {}
gfx::SnesPalette main;
gfx::SnesPalette animated;
gfx::SnesPalette aux1;
gfx::SnesPalette aux2;
gfx::SnesColor background;
gfx::SnesPalette hud;
gfx::SnesPalette spr;
gfx::SnesPalette spr2;
gfx::SnesPalette composite;
};
} // namespace gfx
} // namespace app

View File

@@ -28,13 +28,13 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset,
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)
tile.data[col * 8 + row] |= (uint8_t)((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)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[2]] & mask) == mask)
<< 2;
}
if (bpp >= 4) {
@@ -42,9 +42,9 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset,
// 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)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[2]] & mask) == mask)
<< 2;
tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[3]] & mask) == mask)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[3]] & mask) == mask)
<< 3;
}
if (bpp == 8) {
@@ -52,13 +52,13 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset,
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)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[4]] & mask) == mask)
<< 4;
tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[5]] & mask) == mask)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[5]] & mask) == mask)
<< 5;
tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[6]] & mask) == mask)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[6]] & mask) == mask)
<< 6;
tile.data[col * 8 + row] |= (uchar)((data[bpp_pos[7]] & mask) == mask)
tile.data[col * 8 + row] |= (uint8_t)((data[bpp_pos[7]] & mask) == mask)
<< 7;
}
}
@@ -68,68 +68,70 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset,
Bytes PackBppTile(const tile8& tile, const uint32_t bpp) {
// Allocate memory for output data
std::vector<uchar> output(bpp * 8, 0); // initialized with 0
std::vector<uint8_t> 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];
uint8_t color = tile.data[col * 8 + row];
if (color > maxcolor) {
throw std::invalid_argument("Invalid color value.");
}
// 1bpp format
if (bpp == 1) output[col] += (uchar)((color & 1) << (7 - row));
if (bpp == 1) output[col] += (uint8_t)((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));
output[col * 2] += (uint8_t)((color & 1) << (7 - row));
output[col * 2 + 1] +=
(uint8_t)((uint8_t)((color & 2) == 2) << (7 - row));
}
// 3bpp format
if (bpp == 3)
output[16 + col] += (uchar)(((color & 4) == 4) << (7 - row));
output[16 + col] += (uint8_t)(((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));
output[16 + col * 2] += (uint8_t)(((color & 4) == 4) << (7 - row));
output[16 + col * 2 + 1] += (uint8_t)(((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[32 + col * 2] += (uint8_t)(((color & 16) == 16) << (7 - row));
output[32 + col * 2 + 1] +=
(uint8_t)(((color & 32) == 32) << (7 - row));
output[48 + col * 2] += (uint8_t)(((color & 64) == 64) << (7 - row));
output[48 + col * 2 + 1] +=
(uchar)(((color & 128) == 128) << (7 - row));
(uint8_t)(((color & 128) == 128) << (7 - row));
}
}
}
return output;
}
std::vector<uchar> ConvertBpp(const std::vector<uchar>& tiles,
uint32_t from_bpp, uint32_t to_bpp) {
std::vector<uint8_t> ConvertBpp(const std::vector<uint8_t>& tiles,
uint32_t from_bpp, uint32_t to_bpp) {
unsigned int nb_tile = tiles.size() / (from_bpp * 8);
std::vector<uchar> converted(nb_tile * to_bpp * 8);
std::vector<uint8_t> 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<uchar> packed_tile = PackBppTile(tile, to_bpp);
std::vector<uint8_t> packed_tile = PackBppTile(tile, to_bpp);
std::memcpy(converted.data() + i * to_bpp * 8, packed_tile.data(),
to_bpp * 8);
}
return converted;
}
std::vector<uchar> Convert3bppTo4bpp(const std::vector<uchar>& tiles) {
std::vector<uint8_t> Convert3bppTo4bpp(const std::vector<uint8_t>& tiles) {
return ConvertBpp(tiles, 3, 4);
}
std::vector<uchar> Convert4bppTo3bpp(const std::vector<uchar>& tiles) {
std::vector<uint8_t> Convert4bppTo3bpp(const std::vector<uint8_t>& tiles) {
return ConvertBpp(tiles, 4, 3);
}
@@ -313,34 +315,45 @@ TileInfo WordToTileInfo(uint16_t word) {
return TileInfo(id, palette, vertical_mirror, horizontal_mirror, over);
}
ushort TileInfoToShort(TileInfo tile_info) {
ushort result = 0;
uint16_t TileInfoToShort(TileInfo tile_info) {
// uint16_t result = 0;
// Copy the id_ value
result |= tile_info.id_ & 0x3FF; // ids are 10 bits
// // Copy the id_ value
// result |= tile_info.id_ & 0x3FF; // ids are 10 bits
// Set the vertical_mirror_, horizontal_mirror_, and over_ flags
result |= (tile_info.vertical_mirror_ ? 1 : 0) << 10;
result |= (tile_info.horizontal_mirror_ ? 1 : 0) << 11;
result |= (tile_info.over_ ? 1 : 0) << 12;
// // Set the vertical_mirror_, horizontal_mirror_, and over_ flags
// result |= (tile_info.vertical_mirror_ ? 1 : 0) << 10;
// result |= (tile_info.horizontal_mirror_ ? 1 : 0) << 11;
// result |= (tile_info.over_ ? 1 : 0) << 12;
// Set the palette_
result |= (tile_info.palette_ & 0x07) << 13; // palettes are 3 bits
// // Set the palette_
// result |= (tile_info.palette_ & 0x07) << 13; // palettes are 3 bits
return result;
uint16_t value = 0;
// vhopppcc cccccccc
if (tile_info.over_) {
value |= core::TilePriorityBit;
}
if (tile_info.horizontal_mirror_) {
value |= core::TileHFlipBit;
}
if (tile_info.vertical_mirror_) {
value |= core::TileVFlipBit;
}
value |= (uint16_t)((tile_info.palette_ << 10) & 0x1C00);
value |= (uint16_t)(tile_info.id_ & core::TileNameMask);
return value;
}
TileInfo GetTilesInfo(ushort tile) {
TileInfo GetTilesInfo(uint16_t tile) {
// vhopppcc cccccccc
bool o = false;
bool v = false;
bool h = false;
auto tid = (ushort)(tile & core::TileNameMask);
auto p = (uchar)((tile >> 10) & 0x07);
uint16_t tid = (uint16_t)(tile & core::TileNameMask);
uint8_t p = (uint8_t)((tile >> 10) & 0x07);
o = ((tile & core::TilePriorityBit) == core::TilePriorityBit);
h = ((tile & core::TileHFlipBit) == core::TileHFlipBit);
v = ((tile & core::TileVFlipBit) == core::TileVFlipBit);
bool o = ((tile & core::TilePriorityBit) == core::TilePriorityBit);
bool h = ((tile & core::TileHFlipBit) == core::TileHFlipBit);
bool v = ((tile & core::TileVFlipBit) == core::TileVFlipBit);
return TileInfo(tid, p, v, h, o);
}

View File

@@ -11,8 +11,8 @@ namespace yaze {
namespace app {
namespace gfx {
constexpr uchar kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01};
constexpr uint8_t kGraphicsBitmap[8] = {0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01};
Bytes SnesTo8bppSheet(Bytes sheet, int bpp);
Bytes Bpp8SnesToIndexed(Bytes data, uint64_t bpp = 0);
@@ -29,24 +29,24 @@ tile8 UnpackBppTile(const Bytes& data, const uint32_t offset,
Bytes PackBppTile(const tile8& tile, const uint32_t bpp);
std::vector<uchar> ConvertBpp(const std::vector<uchar>& tiles,
uint32_t from_bpp, uint32_t to_bpp);
std::vector<uint8_t> ConvertBpp(const std::vector<uint8_t>& tiles,
uint32_t from_bpp, uint32_t to_bpp);
std::vector<uchar> Convert3bppTo4bpp(const std::vector<uchar>& tiles);
std::vector<uchar> Convert4bppTo3bpp(const std::vector<uchar>& tiles);
std::vector<uint8_t> Convert3bppTo4bpp(const std::vector<uint8_t>& tiles);
std::vector<uint8_t> Convert4bppTo3bpp(const std::vector<uint8_t>& tiles);
// vhopppcc cccccccc
// [0, 1]
// [2, 3]
class TileInfo {
public:
ushort id_;
uint16_t id_;
uint8_t palette_;
bool over_;
bool vertical_mirror_;
bool horizontal_mirror_;
uchar palette_;
TileInfo() = default;
TileInfo(ushort id, uchar palette, bool v, bool h, bool o)
TileInfo(uint16_t id, uint8_t palette, bool v, bool h, bool o)
: id_(id),
over_(o),
vertical_mirror_(v),
@@ -63,9 +63,9 @@ class TileInfo {
uint16_t TileInfoToWord(TileInfo tile_info);
TileInfo WordToTileInfo(uint16_t word);
ushort TileInfoToShort(TileInfo tile_info);
uint16_t TileInfoToShort(TileInfo tile_info);
TileInfo GetTilesInfo(ushort tile);
TileInfo GetTilesInfo(uint16_t tile);
class Tile32 {
public:
@@ -90,10 +90,17 @@ class Tile32 {
// Constructor from packed value
Tile32(uint64_t packedVal) {
tile0_ = (packedVal >> 48) & 0xFFFF;
tile1_ = (packedVal >> 32) & 0xFFFF;
tile2_ = (packedVal >> 16) & 0xFFFF;
tile3_ = packedVal & 0xFFFF;
tile0_ = (uint16_t)packedVal;
tile1_ = (uint16_t)(packedVal >> 16);
tile2_ = (uint16_t)(packedVal >> 32);
tile3_ = (uint16_t)(packedVal >> 48);
}
// Get packed uint64_t representation
uint64_t GetPackedValue() const {
return static_cast<uint64_t>(tile3_) << 48 |
(static_cast<uint64_t>(tile2_) << 32) |
(static_cast<uint64_t>(tile1_) << 16) | tile0_;
}
// Equality operator
@@ -104,14 +111,6 @@ class Tile32 {
// Inequality operator
bool operator!=(const Tile32& other) const { return !(*this == other); }
// Get packed uint64_t representation
uint64_t GetPackedValue() const {
return (static_cast<uint64_t>(tile0_) << 48) |
(static_cast<uint64_t>(tile1_) << 32) |
(static_cast<uint64_t>(tile2_) << 16) |
static_cast<uint64_t>(tile3_);
}
};
class Tile16 {
@@ -146,15 +145,15 @@ class OAMTile {
int mx_;
int my_;
int pal_;
ushort tile_;
uint16_t tile_;
OAMTile() = default;
OAMTile(int x, int y, ushort tile, int pal, bool upper = false, int mx = 0,
OAMTile(int x, int y, uint16_t tile, int pal, bool upper = false, int mx = 0,
int my = 0)
: x_(x), y_(y), mx_(mx), my_(my), pal_(pal) {
if (upper) {
tile_ = (ushort)(tile + 512);
tile_ = (uint16_t)(tile + 512);
} else {
tile_ = (ushort)(tile + 256 + 512);
tile_ = (uint16_t)(tile + 256 + 512);
}
}
};

0
src/app/gfx/tilesheet.cc Normal file
View File

237
src/app/gfx/tilesheet.h Normal file
View File

@@ -0,0 +1,237 @@
#ifndef YAZE_APP_GFX_TILESHEET_H
#define YAZE_APP_GFX_TILESHEET_H
#include <memory>
#include <vector>
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
namespace yaze {
namespace app {
namespace gfx {
enum class TileType { Tile8, Tile16 };
class Tilesheet {
public:
Tilesheet() = default;
Tilesheet(std::shared_ptr<Bitmap> bitmap, int tileWidth, int tileHeight,
TileType tile_type)
: bitmap_(std::move(bitmap)),
tile_width_(tileWidth),
tile_height_(tileHeight),
tile_type_(tile_type) {}
void Init(int width, int height, TileType tile_type) {
bitmap_ = std::make_shared<Bitmap>(width, height, 8, 0x20000);
internal_data_.resize(0x20000);
tile_type_ = tile_type;
if (tile_type_ == TileType::Tile8) {
tile_width_ = 8;
tile_height_ = 8;
} else {
tile_width_ = 16;
tile_height_ = 16;
}
}
void ComposeTile16(const std::vector<uint8_t>& graphics_buffer,
const TileInfo& top_left, const TileInfo& top_right,
const TileInfo& bottom_left,
const TileInfo& bottom_right) {
// Calculate the base position for this Tile16 in the full-size bitmap
int tiles_per_row = bitmap_->width() / tile_width_;
int tile16_row = num_tiles_ / tiles_per_row;
int tile16_column = num_tiles_ % tiles_per_row;
int baseX = tile16_column * tile_width_;
int baseY = tile16_row * tile_height_;
// Compose and place each part of the Tile16
ComposeAndPlaceTilePart(graphics_buffer, top_left, baseX, baseY);
ComposeAndPlaceTilePart(graphics_buffer, top_right, baseX + 8, baseY);
ComposeAndPlaceTilePart(graphics_buffer, bottom_left, baseX, baseY + 8);
ComposeAndPlaceTilePart(graphics_buffer, bottom_right, baseX + 8,
baseY + 8);
tile_info_.push_back({top_left, top_right, bottom_left, bottom_right});
num_tiles_++;
}
void ComposeAndPlaceTilePart(const std::vector<uint8_t>& graphics_buffer,
const TileInfo& tile_info, int baseX,
int baseY) {
std::vector<uint8_t> tile_data =
FetchTileDataFromGraphicsBuffer(graphics_buffer, tile_info.id_);
if (tile_info.vertical_mirror_) {
MirrorTileDataVertically(tile_data);
}
if (tile_info.horizontal_mirror_) {
MirrorTileDataHorizontally(tile_data);
}
// Place the tile data into the full-size bitmap at the calculated position
for (int y = 0; y < 8; ++y) {
for (int x = 0; x < 8; ++x) {
int srcIndex = y * 8 + x;
int destX = baseX + x;
int destY = baseY + y;
int destIndex = (destY * bitmap_->width()) + destX;
internal_data_[destIndex] = tile_data[srcIndex];
}
}
bitmap_->set_data(internal_data_);
}
// Extracts a tile from the tilesheet
Bitmap GetTile(int tileX, int tileY, int bmp_width, int bmp_height) {
std::vector<uint8_t> tileData(tile_width_ * tile_height_);
int tileDataOffset = 0;
bitmap_->Get8x8Tile(CalculateTileIndex(tileX, tileY), tileX, tileY,
tileData, tileDataOffset);
return Bitmap(bmp_width, bmp_height, bitmap_->depth(), tileData);
}
Bitmap GetTile16(int tile_x, int tile_y) {
std::vector<uint8_t> tile_data(tile_width_ * tile_height_, 0x00);
int tileDataOffset = 0;
bitmap_->Get16x16Tile(tile_x, tile_y, tile_data, tileDataOffset);
return Bitmap(16, 16, bitmap_->depth(), tile_data);
}
Bitmap GetTile16(int tile_id) {
int tiles_per_row = bitmap_->width() / tile_width_;
int tile_x = (tile_id % tiles_per_row) * tile_width_;
int tile_y = (tile_id / tiles_per_row) * tile_height_;
return GetTile16(tile_x, tile_y);
}
// Copy a tile within the tilesheet
void CopyTile(int srcX, int srcY, int destX, int destY, bool mirrorX = false,
bool mirrorY = false) {
auto srcTile = GetTile(srcX, srcY, tile_width_, tile_height_);
auto destTileData = srcTile.vector();
MirrorTileData(destTileData, mirrorX, mirrorY);
WriteTile(destX, destY, destTileData);
}
// Other methods and properties
auto bitmap() const { return bitmap_; }
auto mutable_bitmap() { return bitmap_; }
auto num_tiles() const { return num_tiles_; }
auto tile_width() const { return tile_width_; }
auto tile_height() const { return tile_height_; }
auto set_palette(gfx::SnesPalette& palette) { palette_ = palette; }
auto palette() const { return palette_; }
auto tile_type() const { return tile_type_; }
auto tile_info() const { return tile_info_; }
auto mutable_tile_info() { return tile_info_; }
private:
int CalculateTileIndex(int x, int y) {
return y * (bitmap_->width() / tile_width_) + x;
}
std::vector<uint8_t> FetchTileDataFromGraphicsBuffer(
const std::vector<uint8_t>& graphics_buffer, int tile_id) {
const int tileWidth = 8;
const int tileHeight = 8;
const int bufferWidth = 128;
const int sheetHeight = 32;
const int tilesPerRow = bufferWidth / tileWidth;
const int rowsPerSheet = sheetHeight / tileHeight;
const int tilesPerSheet = tilesPerRow * rowsPerSheet;
// Calculate the position in the graphics_buffer_ based on tile_id
std::vector<uint8_t> tile_data(0x40, 0x00);
int sheet = (tile_id / tilesPerSheet) % 4 + 212;
int positionInSheet = tile_id % tilesPerSheet;
int rowInSheet = positionInSheet / tilesPerRow;
int columnInSheet = positionInSheet % tilesPerRow;
// Ensure that the sheet ID is between 212 and 215
assert(sheet >= 212 && sheet <= 215);
// Copy the tile data from the graphics_buffer_ to tile_data
for (int y = 0; y < 8; ++y) {
for (int x = 0; x < 8; ++x) {
// Calculate the position in the graphics_buffer_ based on tile_id
int srcX = columnInSheet * tileWidth + x;
int srcY = (sheet * sheetHeight) + (rowInSheet * tileHeight) + y;
int src_index = (srcY * bufferWidth) + srcX;
int dest_index = y * tileWidth + x;
tile_data[dest_index] = graphics_buffer[src_index];
}
}
return tile_data;
}
void MirrorTileDataVertically(std::vector<uint8_t>& tileData) {
std::vector<uint8_t> tile_data_copy = tileData;
for (int i = 0; i < 8; ++i) { // For each row
for (int j = 0; j < 8; ++j) { // For each column
int src_index = i * 8 + j;
int dest_index = (7 - i) * 8 + j; // Calculate the mirrored row
tile_data_copy[dest_index] = tileData[src_index];
}
}
tileData = tile_data_copy;
}
void MirrorTileDataHorizontally(std::vector<uint8_t>& tileData) {
std::vector<uint8_t> tile_data_copy = tileData;
for (int i = 0; i < 8; ++i) { // For each row
for (int j = 0; j < 8; ++j) { // For each column
int src_index = i * 8 + j;
int dest_index = i * 8 + (7 - j); // Calculate the mirrored column
tile_data_copy[dest_index] = tileData[src_index];
}
}
tileData = tile_data_copy;
}
void MirrorTileData(std::vector<uint8_t>& tileData, bool mirrorX,
bool mirrorY) {
// Implement logic to mirror tile data horizontally and/or vertically
std::vector tile_data_copy = tileData;
if (mirrorX) {
MirrorTileDataHorizontally(tile_data_copy);
}
if (mirrorY) {
MirrorTileDataVertically(tile_data_copy);
}
tileData = tile_data_copy;
}
void WriteTile(int x, int y, const std::vector<uint8_t>& tileData) {
int tileDataOffset = 0;
bitmap_->Get8x8Tile(CalculateTileIndex(x, y), x, y,
const_cast<std::vector<uint8_t>&>(tileData),
tileDataOffset);
}
gfx::SnesPalette palette_;
std::vector<uint8_t> internal_data_;
std::shared_ptr<Bitmap> bitmap_;
struct InternalTile16 {
std::array<TileInfo, 4> tiles;
};
std::vector<InternalTile16> tile_info_;
int num_tiles_ = 0;
int tile_width_ = 0;
int tile_height_ = 0;
TileType tile_type_;
};
} // namespace gfx
} // namespace app
} // namespace yaze
#endif // YAZE_APP_GFX_TILESHEET_H