backend-infra-engineer: Pre-0.2.2 2024 Q1 snapshot
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
104
src/app/gfx/snes_color.cc
Normal 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
99
src/app/gfx/snes_color.h
Normal 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_
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
0
src/app/gfx/tilesheet.cc
Normal file
237
src/app/gfx/tilesheet.h
Normal file
237
src/app/gfx/tilesheet.h
Normal 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
|
||||
Reference in New Issue
Block a user