Update SNESPalette, SNESColor, add tests

This commit is contained in:
scawful
2023-08-04 22:51:12 -04:00
parent 7d0b09a589
commit 9ea107bc8d
17 changed files with 299 additions and 263 deletions

View File

@@ -54,6 +54,15 @@
} \
}
#define EXIT_IF_ERROR(expression) \
{ \
auto error = expression; \
if (!error.ok()) { \
std::cout << error.ToString() << std::endl; \
return EXIT_FAILURE; \
} \
}
#define RETURN_IF_ERROR(expression) \
{ \
auto error = expression; \

View File

@@ -30,7 +30,7 @@ void SelectablePalettePipeline(uint64_t& palette_id, bool& refresh_graphics,
ImGui::PushID(n);
if ((n % 8) != 0) ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
if (ImGui::ColorButton("##palette", palette[n].RGB(),
if (ImGui::ColorButton("##palette", palette[n].GetRGB(),
ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_NoPicker |
ImGuiColorEditFlags_NoTooltip,

View File

@@ -276,7 +276,7 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
if (rom_.isLoaded()) {
auto palette_group = rom_.GetPaletteGroup("ow_main");
palette_ = palette_group.palettes[current_palette_];
palette_ = palette_group[current_palette_];
if (col_file_) {
bitmap_.ApplyPalette(col_file_palette_);
} else {
@@ -309,7 +309,7 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
// ROM palette
auto palette_group =
rom_.GetPaletteGroup(kPaletteGroupAddressesKeys[current_palette_]);
palette_ = palette_group.palettes[current_palette_index_];
palette_ = palette_group[current_palette_index_];
graphics_bin_[i].ApplyPalette(palette_);
}
@@ -334,7 +334,7 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
// ROM palette
auto palette_group =
rom_.GetPaletteGroup(kPaletteGroupAddressesKeys[current_palette_]);
palette_ = palette_group.palettes[current_palette_index_];
palette_ = palette_group[current_palette_index_];
graphics_bin_[i].ApplyPalette(palette_);
}

View File

@@ -352,11 +352,11 @@ absl::Status OverworldEditor::LoadGraphics() {
absl::Status OverworldEditor::LoadSpriteGraphics() {
// Render the sprites for each Overworld map
for (int i = 0; i < 3; i++)
for (auto &sprite : overworld_.Sprites(i)) {
for (auto const &sprite : overworld_.Sprites(i)) {
int width = sprite.Width();
int height = sprite.Height();
int depth = 0x40;
auto spr_gfx = sprite.PreviewGraphics().data();
auto spr_gfx = sprite.PreviewGraphics();
sprite_previews_[sprite.id()].Create(width, height, depth, spr_gfx);
sprite_previews_[sprite.id()].ApplyPalette(palette_);
rom_.RenderBitmap(&(sprite_previews_[sprite.id()]));

View File

@@ -33,13 +33,6 @@ namespace yaze {
namespace app {
namespace editor {
namespace {
void DrawPaletteTooltips(gfx::SNESPalette& palette, int size) {}
using namespace ImGui;
} // namespace
absl::Status PaletteEditor::Update() {
for (int i = 0; i < kNumPalettes; ++i) {
if (ImGui::TreeNode(kPaletteCategoryNames[i].data())) {
@@ -57,7 +50,7 @@ void PaletteEditor::DrawPaletteGroup(int i) {
ImGui::Text("%d", j);
auto palette = palettes[j];
auto pal_size = palette.size_;
auto pal_size = palette.size();
for (int n = 0; n < pal_size; n++) {
ImGui::PushID(n);
@@ -65,38 +58,39 @@ void PaletteEditor::DrawPaletteGroup(int i) {
std::string popupId = kPaletteCategoryNames[i].data() +
std::to_string(j) + "_" + std::to_string(n);
if (ImGui::ColorButton(popupId.c_str(), palette[n].RGB(),
if (ImGui::ColorButton(popupId.c_str(), palette[n].GetRGB(),
palette_button_flags)) {
if (ImGui::ColorEdit4(popupId.c_str(), palette[n].ToFloatArray(),
static auto float_array = gfx::ToFloatArray(palette[n]);
if (ImGui::ColorEdit4(popupId.c_str(), float_array.data(),
palette_button_flags))
current_color_ =
ImVec4(palette[n].rgb.x, palette[n].rgb.y, palette[n].rgb.z,
palette[n].rgb.w); // Prese rve alpha!
current_color_ = ImVec4(palette[n].GetRGB().x, palette[n].GetRGB().y,
palette[n].GetRGB().z,
palette[n].GetRGB().w); // Prese rve alpha!
}
if (ImGui::BeginPopupContextItem(popupId.c_str())) {
auto col = palette[n].ToFloatArray();
auto col = gfx::ToFloatArray(palette[n]);
if (ImGui::ColorEdit4(
"Edit Color", col,
"Edit Color", col.data(),
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha)) {
rom_.UpdatePaletteColor(kPaletteGroupNames[i].data(), j, n,
palette[n]);
}
if (Button("Copy as..", ImVec2(-1, 0))) OpenPopup("Copy");
if (BeginPopup("Copy")) {
if (ImGui::Button("Copy as..", ImVec2(-1, 0))) ImGui::OpenPopup("Copy");
if (ImGui::BeginPopup("Copy")) {
int cr = IM_F32_TO_INT8_SAT(col[0]);
int cg = IM_F32_TO_INT8_SAT(col[1]);
int cb = IM_F32_TO_INT8_SAT(col[2]);
char buf[64];
CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff)",
col[0], col[1], col[2]);
if (Selectable(buf)) SetClipboardText(buf);
if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf);
CustomFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d)", cr, cg, cb);
if (Selectable(buf)) SetClipboardText(buf);
if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf);
CustomFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg,
cb);
if (Selectable(buf)) SetClipboardText(buf);
EndPopup();
if (ImGui::Selectable(buf)) ImGui::SetClipboardText(buf);
ImGui::EndPopup();
}
ImGui::EndPopup();
@@ -116,10 +110,10 @@ void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) {
// Generate a default palette. The palette will persist and can be edited.
static bool init = false;
if (loaded && !init) {
for (int n = 0; n < palette.size_; n++) {
saved_palette_[n].x = palette.GetColor(n).rgb.x / 255;
saved_palette_[n].y = palette.GetColor(n).rgb.y / 255;
saved_palette_[n].z = palette.GetColor(n).rgb.z / 255;
for (int n = 0; n < palette.size(); n++) {
saved_palette_[n].x = palette.GetColor(n).GetRGB().x / 255;
saved_palette_[n].y = palette.GetColor(n).GetRGB().y / 255;
saved_palette_[n].z = palette.GetColor(n).GetRGB().z / 255;
saved_palette_[n].w = 255; // Alpha
}
init = true;
@@ -193,10 +187,10 @@ void PaletteEditor::DisplayPalette(gfx::SNESPalette& palette, bool loaded) {
void PaletteEditor::DrawPortablePalette(gfx::SNESPalette& palette) {
static bool init = false;
if (!init) {
for (int n = 0; n < palette.size_; n++) {
saved_palette_[n].x = palette.GetColor(n).rgb.x / 255;
saved_palette_[n].y = palette.GetColor(n).rgb.y / 255;
saved_palette_[n].z = palette.GetColor(n).rgb.z / 255;
for (int n = 0; n < palette.size(); n++) {
saved_palette_[n].x = palette.GetColor(n).GetRGB().x / 255;
saved_palette_[n].y = palette.GetColor(n).GetRGB().y / 255;
saved_palette_[n].z = palette.GetColor(n).GetRGB().z / 255;
saved_palette_[n].w = 255; // Alpha
}
init = true;

View File

@@ -128,17 +128,17 @@ void Bitmap::UpdateTexture(std::shared_ptr<SDL_Renderer> renderer) {
void Bitmap::ApplyPalette(const SNESPalette &palette) {
palette_ = palette;
SDL_UnlockSurface(surface_.get());
for (int i = 0; i < palette.size_; ++i) {
if (palette.GetColor(i).transparent) {
for (int i = 0; i < palette.size(); ++i) {
if (palette.GetColor(i).isTransparent()) {
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;
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;
}
}
SDL_LockSurface(surface_.get());

View File

@@ -16,57 +16,62 @@ namespace yaze {
namespace app {
namespace gfx {
ushort ConvertRGBtoSNES(const snes_color color) {
uchar red = color.red / 8;
uchar green = color.green / 8;
uchar blue = color.blue / 8;
return blue * 1024 + green * 32 + red;
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;
}
snes_color ConvertSNEStoRGB(const ushort color) {
snes_color toret;
snes_color ConvertSNEStoRGB(uint16_t color_snes) {
snes_color result;
toret.red = ((color) % 32) * 8;
toret.green = ((color / 32) % 32) * 8;
toret.blue = ((color / 1024) % 32) * 8;
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;
toret.red = toret.red + toret.red / 32;
toret.green = toret.green + toret.green / 32;
toret.blue = toret.blue + toret.blue / 32;
return toret;
result.red += result.red / SNES_RED_MASK;
result.green += result.green / SNES_GREEN_MASK;
result.blue += result.blue / SNES_BLUE_MASK;
return result;
}
snes_palette* Extract(const char* data, const unsigned int offset,
const unsigned int palette_size) {
snes_palette* toret = nullptr; // palette_create(palette_size, 0)
unsigned colnum = 0;
for (int i = 0; i < palette_size * 2; i += 2) {
unsigned short snes_color;
snes_color = ((uchar)data[offset + i + 1]) << 8;
snes_color = snes_color | ((uchar)data[offset + i]);
toret->colors[colnum] = ConvertSNEStoRGB(snes_color);
colnum++;
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 toret;
return palette;
}
char* Convert(const snes_palette pal) {
char* toret = (char*)malloc(pal.size * 2);
for (unsigned int i = 0; i < pal.size; i++) {
unsigned short snes_data = ConvertRGBtoSNES(pal.colors[i]);
toret[i * 2] = snes_data & 0xFF;
toret[i * 2 + 1] = snes_data >> 8;
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 toret;
return data;
}
SNESColor GetCgxColor(short 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);
toret.SetRGB(rgb);
return toret;
}
@@ -76,7 +81,7 @@ std::vector<SNESColor> GetColFileData(uchar* data) {
colors.resize(256);
for (int i = 0; i < 512; i += 2) {
colors[i / 2] = GetCgxColor((short)((data[i + 1] << 8) + data[i]));
colors[i / 2] = GetCgxColor((uint16_t)((data[i + 1] << 8) + data[i]));
}
return colors;
@@ -84,43 +89,6 @@ std::vector<SNESColor> GetColFileData(uchar* data) {
// ============================================================================
SNESColor::SNESColor() : rgb(ImVec4(0.f, 0.f, 0.f, 0.f)) {}
SNESColor::SNESColor(snes_color val) {
rgb.x = val.red;
rgb.y = val.green;
rgb.z = val.blue;
}
SNESColor::SNESColor(ImVec4 val) : rgb(val) {
snes_color col;
col.red = (uchar)val.x;
col.blue = (uchar)val.y;
col.green = (uchar)val.z;
snes = ConvertRGBtoSNES(col);
}
void SNESColor::setRgb(ImVec4 val) {
rgb = val;
snes_color col;
col.red = val.x;
col.blue = val.y;
col.green = val.z;
snes = ConvertRGBtoSNES(col);
}
void SNESColor::setSNES(snes_color val) {
rgb = ImVec4(val.red, val.green, val.blue, 255.f);
}
void SNESColor::setSNES(uint16_t val) {
snes = val;
snes_color col = ConvertSNEStoRGB(val);
rgb = ImVec4(col.red, col.green, col.blue, 0.f);
}
// ============================================================================
SNESPalette::SNESPalette(uint8_t mSize) : size_(mSize) {
for (unsigned int i = 0; i < mSize; i++) {
SNESColor col;
@@ -132,10 +100,10 @@ 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.snes = static_cast<uchar>(data[i + 1]) << 8;
col.snes = col.snes | static_cast<uchar>(data[i]);
snes_color mColor = ConvertSNEStoRGB(col.snes);
col.rgb = ImVec4(mColor.red, mColor.green, mColor.blue, 1.f);
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);
}
}
@@ -145,10 +113,10 @@ SNESPalette::SNESPalette(const unsigned char* snes_pal)
assert((sizeof(snes_pal) % 4 == 0) && (sizeof(snes_pal) <= 32));
for (unsigned i = 0; i < sizeof(snes_pal); i += 2) {
SNESColor col;
col.snes = snes_pal[i + 1] << (uint16_t)8;
col.snes = col.snes | snes_pal[i];
snes_color mColor = ConvertSNEStoRGB(col.snes);
col.rgb = ImVec4(mColor.red, mColor.green, mColor.blue, 1.f);
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);
}
}
@@ -156,7 +124,7 @@ SNESPalette::SNESPalette(const unsigned char* snes_pal)
SNESPalette::SNESPalette(const std::vector<ImVec4>& cols) {
for (const auto& each : cols) {
SNESColor scol;
scol.setRgb(each);
scol.SetRGB(each);
colors.push_back(scol);
}
size_ = cols.size();
@@ -165,7 +133,7 @@ SNESPalette::SNESPalette(const std::vector<ImVec4>& cols) {
SNESPalette::SNESPalette(const std::vector<snes_color>& cols) {
for (const auto& each : cols) {
SNESColor scol;
scol.setSNES(each);
scol.SetSNES(ConvertRGBtoSNES(each));
colors.push_back(scol);
}
size_ = cols.size();
@@ -178,19 +146,11 @@ SNESPalette::SNESPalette(const std::vector<SNESColor>& cols) {
size_ = cols.size();
}
void SNESPalette::Create(const std::vector<SNESColor>& cols) {
for (const auto each : cols) {
colors.push_back(each);
}
size_ = cols.size();
}
char* SNESPalette::encode() {
auto data = new char[size_ * 2];
for (unsigned int i = 0; i < size_; i++) {
std::cout << colors[i].snes << std::endl;
data[i * 2] = (char)(colors[i].snes & 0xFF);
data[i * 2 + 1] = (char)(colors[i].snes >> 8);
data[i * 2] = (char)(colors[i].GetSNES() & 0xFF);
data[i * 2 + 1] = (char)(colors[i].GetSNES() >> 8);
}
return data;
}
@@ -201,9 +161,9 @@ SDL_Palette* SNESPalette::GetSDL_Palette() {
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].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;
@@ -212,6 +172,15 @@ SDL_Palette* SNESPalette::GetSDL_Palette() {
return sdl_palette.get();
}
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;
return colorArray;
}
PaletteGroup::PaletteGroup(uint8_t mSize) : size_(mSize) {}
PaletteGroup CreatePaletteGroupFromColFile(
@@ -221,7 +190,7 @@ PaletteGroup CreatePaletteGroupFromColFile(
for (int i = 0; i < palette_rows.size(); i += 8) {
SNESPalette palette;
for (int j = 0; j < 8; j++) {
palette.AddColor(palette_rows[i + j]);
palette.AddColor(palette_rows[i + j].GetRomRGB());
}
toret.AddPalette(palette);
}

View File

@@ -11,6 +11,7 @@
#include <memory>
#include <vector>
#include "absl/base/casts.h"
#include "app/core/constants.h"
namespace yaze {
@@ -18,9 +19,9 @@ namespace app {
namespace gfx {
struct snes_color {
uchar red;
uchar blue;
uchar green;
uint16_t red;
uint16_t blue;
uint16_t green;
};
using snes_color = struct snes_color;
@@ -31,47 +32,80 @@ struct snes_palette {
};
using snes_palette = struct snes_palette;
ushort ConvertRGBtoSNES(const snes_color color);
snes_color ConvertSNEStoRGB(const ushort snes_color);
snes_palette* Extract(const char* data, const unsigned int offset,
const unsigned int palette_size);
char* Convert(const snes_palette pal);
uint16_t ConvertRGBtoSNES(const snes_color& color);
snes_color ConvertSNEStoRGB(uint16_t snes_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);
struct SNESColor {
SNESColor();
explicit SNESColor(ImVec4);
explicit SNESColor(snes_color);
SNESColor() : rgb(0.f, 0.f, 0.f, 0.f), snes(0) {}
void setRgb(ImVec4);
void setSNES(snes_color);
void setSNES(uint16_t);
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;
}
// Used for indexed Bitmaps from CGX files
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; }
auto RGB() const {
return ImVec4(rgb.x / 255, rgb.y / 255, rgb.z / 255, rgb.w);
}
float* ToFloatArray() {
static std::vector<float> colorArray(4);
colorArray[0] = rgb.x / 255.0f;
colorArray[1] = rgb.y / 255.0f;
colorArray[2] = rgb.z / 255.0f;
colorArray[3] = rgb.w;
return colorArray.data();
}
private:
ImVec4 rgb;
uint16_t snes;
snes_color rom_color;
bool modified = false;
bool transparent = false;
uint16_t snes = 0;
ImVec4 rgb;
};
SNESColor GetCgxColor(short color);
SNESColor GetCgxColor(uint16_t color);
std::vector<SNESColor> GetColFileData(uchar* data);
class SNESPalette {
public:
template <typename T>
explicit SNESPalette(const std::vector<T>& data) {
for (const auto& item : data) {
colors.push_back(SNESColor(item));
}
}
SNESPalette() = default;
explicit SNESPalette(uint8_t mSize);
explicit SNESPalette(char* snesPal);
@@ -80,70 +114,92 @@ class SNESPalette {
explicit SNESPalette(const std::vector<snes_color>&);
explicit SNESPalette(const std::vector<SNESColor>&);
void Create(const std::vector<SNESColor>&);
char* encode();
SDL_Palette* GetSDL_Palette();
void Create(const std::vector<SNESColor>& cols) {
for (const auto each : cols) {
colors.push_back(each);
}
size_ = cols.size();
}
void AddColor(SNESColor color) {
colors.push_back(color);
size_++;
}
auto GetColor(int i) const { return colors[i]; }
void AddColor(snes_color color) {
colors.emplace_back(color);
size_++;
}
auto GetColor(int i) const {
if (i > size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
}
return colors[i];
}
void Clear() {
colors.clear();
size_ = 0;
}
auto size() const { return colors.size(); }
SNESColor operator[](int i) {
if (i > size_) {
std::cout << "SNESPalette: Index out of bounds" << std::endl;
return colors[0];
throw std::out_of_range("SNESPalette: Index out of bounds");
}
return colors[i];
}
void operator()(int i, const SNESColor& color) {
if (i >= size_) {
std::cout << "SNESPalette: Index out of bounds" << std::endl;
return;
throw std::out_of_range("SNESPalette: Index out of bounds");
}
colors[i] = color;
}
void operator()(int i, const ImVec4& color) {
if (i >= size_) {
std::cout << "SNESPalette: Index out of bounds" << std::endl;
return;
throw std::out_of_range("SNESPalette: Index out of bounds");
}
colors[i].rgb.x = color.x;
colors[i].rgb.y = color.y;
colors[i].rgb.z = color.z;
colors[i].rgb.w = color.w;
colors[i].modified = true;
colors[i].SetRGB(color);
colors[i].setModified(true);
}
char* encode();
SDL_Palette* GetSDL_Palette();
private:
int size_ = 0;
auto size() const { return colors.size(); }
std::vector<SNESColor> colors;
};
std::array<float, 4> ToFloatArray(const SNESColor& color);
struct PaletteGroup {
PaletteGroup() = default;
explicit PaletteGroup(uint8_t mSize);
void AddPalette(SNESPalette pal) {
palettes.emplace_back(pal);
size_ = palettes.size();
}
void AddColor(SNESColor color) {
if (size_ == 0) {
palettes.emplace_back();
}
palettes[0].AddColor(color);
}
void Clear() {
palettes.clear();
size_ = 0;
}
auto size() const { return palettes.size(); }
SNESPalette operator[](int i) {
if (i > size_) {
std::cout << "PaletteGroup: Index out of bounds" << std::endl;
@@ -151,8 +207,9 @@ struct PaletteGroup {
}
return palettes[i];
}
private:
int size_ = 0;
auto size() const { return palettes.size(); }
std::vector<SNESPalette> palettes;
};

View File

@@ -21,10 +21,10 @@ void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded) {
static bool init = false;
static ImVec4 saved_palette[32] = {};
if (loaded && !init) {
for (int n = 0; n < palette.size_; n++) {
saved_palette[n].x = palette.GetColor(n).rgb.x / 255;
saved_palette[n].y = palette.GetColor(n).rgb.y / 255;
saved_palette[n].z = palette.GetColor(n).rgb.z / 255;
for (int n = 0; n < palette.size(); n++) {
saved_palette[n].x = palette.GetColor(n).GetRGB().x / 255;
saved_palette[n].y = palette.GetColor(n).GetRGB().y / 255;
saved_palette[n].z = palette.GetColor(n).GetRGB().z / 255;
saved_palette[n].w = 255; // Alpha
}
init = true;

View File

@@ -470,9 +470,9 @@ void ROM::SaveAllPalettes() {
for (size_t j = 0; j < palette.size(); ++j) {
gfx::SNESColor color = palette[j];
// If the color is modified, save the color to the ROM
if (color.modified) {
if (color.isModified()) {
WriteColor(GetPaletteAddress(groupName, i, j), color);
color.modified = false; // Reset the modified flag after saving
color.setModified(false); // Reset the modified flag after saving
}
}
}
@@ -561,7 +561,7 @@ gfx::SNESPalette ROM::ReadPalette(int offset, int num_colors) {
new_color.red = (color & 0x1F) * 8;
new_color.green = ((color >> 5) & 0x1F) * 8;
new_color.blue = ((color >> 10) & 0x1F) * 8;
colors[color_offset].setSNES(new_color);
colors[color_offset].SetSNES(gfx::ConvertRGBtoSNES(new_color));
color_offset++;
offset += 2;
}
@@ -582,8 +582,8 @@ void ROM::WriteShort(int addr, int value) {
// ============================================================================
void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) {
uint16_t bgr = ((color.snes >> 10) & 0x1F) | ((color.snes & 0x1F) << 10) |
(color.snes & 0x7C00);
uint16_t bgr = ((color.GetSNES() >> 10) & 0x1F) |
((color.GetSNES() & 0x1F) << 10) | (color.GetSNES() & 0x7C00);
// Write the 16-bit color value to the ROM at the specified address
rom_data_[address] = static_cast<uint8_t>(bgr & 0xFF);
@@ -607,20 +607,5 @@ uint32_t ROM::GetPaletteAddress(const std::string& groupName,
return address;
}
// ============================================================================
absl::Status ROM::ApplyAssembly(const absl::string_view& filename,
uint32_t size) {
// int count = 0;
// auto patch = filename.data();
// auto data = (char*)rom_data_.data();
// if (int size = size_; !asar_patch(patch, data, patch_size, &size)) {
// auto asar_error = asar_geterrors(&count);
// auto full_error = asar_error->fullerrdata;
// return absl::InternalError(absl::StrCat("ASAR Error: ", full_error));
// }
return absl::OkStatus();
}
} // namespace app
} // namespace yaze

View File

@@ -69,9 +69,6 @@ const absl::flat_hash_map<std::string, uint32_t> paletteGroupColorCounts = {
class ROM {
public:
// Assembly functions
absl::Status ApplyAssembly(const absl::string_view& filename, uint32_t size);
// Compression function
absl::StatusOr<Bytes> Compress(const int start, const int length,
int mode = 1, bool check = false);

View File

@@ -10,16 +10,13 @@ int main(int argc, char** argv) {
absl::InitializeSymbolizer(argv[0]);
absl::FailureSignalHandlerOptions options;
options.symbolize_stacktrace = true;
options.alarm_on_failure_secs = true;
absl::InstallFailureSignalHandler(options);
yaze::app::core::Controller controller;
auto entry_status = controller.OnEntry();
if (!entry_status.ok()) {
// TODO(@scawful): log the specific error
return EXIT_FAILURE;
}
EXIT_IF_ERROR(controller.OnEntry())
while (controller.IsActive()) {
controller.OnInput();
controller.OnLoad();

View File

@@ -11,17 +11,17 @@ namespace {
uint GetOwMapGfxHighPtr(const uchar *rom, int index) {
int map_high_ptr = core::compressedAllMap32PointersHigh;
int p1 = (rom[(map_high_ptr) + 2 + (3 * index)] << 16) +
(rom[(map_high_ptr) + 1 + (3 * index)] << 8) +
(rom[(map_high_ptr + (3 * index))]);
int p1 = (rom[map_high_ptr + 2 + (3 * index)] << 16) +
(rom[map_high_ptr + 1 + (3 * index)] << 8) +
(rom[map_high_ptr + (3 * index)]);
return core::SnesToPc(p1);
}
uint GetOwMapGfxLowPtr(const uchar *rom, int index) {
int map_low_ptr = core::compressedAllMap32PointersLow;
int p2 = (rom[(map_low_ptr) + 2 + (3 * index)] << 16) +
(rom[(map_low_ptr) + 1 + (3 * index)] << 8) +
(rom[(map_low_ptr + (3 * index))]);
int p2 = (rom[map_low_ptr + 2 + (3 * index)] << 16) +
(rom[map_low_ptr + 1 + (3 * index)] << 8) +
(rom[map_low_ptr + (3 * index)]);
return core::SnesToPc(p2);
}
@@ -360,13 +360,13 @@ void Overworld::AssembleMap32Tiles() {
void Overworld::AssembleMap16Tiles() {
int tpos = core::map16Tiles;
for (int i = 0; i < 4096; i += 1) {
auto t0 = gfx::GetTilesInfo((rom_.toint16(tpos)));
auto t0 = gfx::GetTilesInfo(rom_.toint16(tpos));
tpos += 2;
auto t1 = gfx::GetTilesInfo((rom_.toint16(tpos)));
auto t1 = gfx::GetTilesInfo(rom_.toint16(tpos));
tpos += 2;
auto t2 = gfx::GetTilesInfo((rom_.toint16(tpos)));
auto t2 = gfx::GetTilesInfo(rom_.toint16(tpos));
tpos += 2;
auto t3 = gfx::GetTilesInfo((rom_.toint16(tpos)));
auto t3 = gfx::GetTilesInfo(rom_.toint16(tpos));
tpos += 2;
tiles16.emplace_back(t0, t1, t2, t3);
}
@@ -393,8 +393,7 @@ void Overworld::OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx,
for (int y = 0; y < 16; y++) {
for (int x = 0; x < 16; x++) {
auto tidD = (ushort)((bytes2[ttpos] << 8) + bytes[ttpos]);
int tpos = tidD;
if (tpos < tiles32.size()) {
if (int tpos = tidD; tpos < tiles32.size()) {
if (i < 64) {
AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.light_world);
} else if (i < 128 && i >= 64) {

View File

@@ -14,7 +14,7 @@ add_executable(
yaze_test
yaze_test.cc
compression_test.cc
rom_test.cc
snes_palette_test.cc
../src/app/rom.cc
../src/app/gfx/bitmap.cc
../src/app/gfx/snes_tile.cc

View File

@@ -59,7 +59,7 @@ std::shared_ptr<CompressionPiece> ExpectNewCompressionPieceOk(
} // namespace
TEST(GFXTest, NewDecompressionPieceOk) {
TEST(LC_LZ2_CompressionTest, NewDecompressionPieceOk) {
char command = 1;
int length = 1;
char args[] = "aaa";
@@ -81,7 +81,7 @@ TEST(GFXTest, NewDecompressionPieceOk) {
}
}
TEST(GFXTest, DecompressionValidCommand) {
TEST(LC_LZ2_CompressionTest, DecompressionValidCommand) {
ROM rom;
Bytes simple_copy_input = {BUILD_HEADER(0x00, 0x02), 0x2A, 0x45, 0xFF};
uchar simple_copy_output[2] = {0x2A, 0x45};
@@ -89,7 +89,7 @@ TEST(GFXTest, DecompressionValidCommand) {
EXPECT_THAT(simple_copy_output, ElementsAreArray(decomp_result.data(), 2));
}
TEST(GFXTest, DecompressionMixingCommand) {
TEST(LC_LZ2_CompressionTest, DecompressionMixingCommand) {
ROM rom;
uchar random1_i[11] = {BUILD_HEADER(0x01, 0x03),
0x2A,
@@ -107,7 +107,7 @@ TEST(GFXTest, DecompressionMixingCommand) {
EXPECT_THAT(random1_o, ElementsAreArray(decomp_result.data(), 9));
}
TEST(GFXTest, CompressionSingleSet) {
TEST(LC_LZ2_CompressionTest, CompressionSingleSet) {
ROM rom;
uchar single_set[5] = {0x2A, 0x2A, 0x2A, 0x2A, 0x2A};
uchar single_set_expected[3] = {BUILD_HEADER(1, 5), 0x2A, 0xFF};
@@ -116,7 +116,7 @@ TEST(GFXTest, CompressionSingleSet) {
EXPECT_THAT(single_set_expected, ElementsAreArray(comp_result.data(), 3));
}
TEST(GFXTest, CompressionSingleWord) {
TEST(LC_LZ2_CompressionTest, CompressionSingleWord) {
ROM rom;
uchar single_word[6] = {0x2A, 0x01, 0x2A, 0x01, 0x2A, 0x01};
uchar single_word_expected[4] = {BUILD_HEADER(0x02, 0x06), 0x2A, 0x01, 0xFF};
@@ -125,7 +125,7 @@ TEST(GFXTest, CompressionSingleWord) {
EXPECT_THAT(single_word_expected, ElementsAreArray(comp_result.data(), 4));
}
TEST(GFXTest, CompressionSingleIncrement) {
TEST(LC_LZ2_CompressionTest, CompressionSingleIncrement) {
ROM rom;
uchar single_inc[3] = {0x01, 0x02, 0x03};
uchar single_inc_expected[3] = {BUILD_HEADER(0x03, 0x03), 0x01, 0xFF};
@@ -133,7 +133,7 @@ TEST(GFXTest, CompressionSingleIncrement) {
EXPECT_THAT(single_inc_expected, ElementsAreArray(comp_result.data(), 3));
}
TEST(GFXTest, CompressionSingleCopy) {
TEST(LC_LZ2_CompressionTest, CompressionSingleCopy) {
ROM rom;
uchar single_copy[4] = {0x03, 0x0A, 0x07, 0x14};
uchar single_copy_expected[6] = {
@@ -143,7 +143,7 @@ TEST(GFXTest, CompressionSingleCopy) {
}
/* Hiding tests until I figure out a better PR to address the bug
TEST(GFXTest, CompressionSingleCopyRepeat) {
TEST(LC_LZ2_CompressionTest, CompressionSingleCopyRepeat) {
ROM rom;
uchar single_copy_repeat[8] = {0x03, 0x0A, 0x07, 0x14, 0x03, 10, 0x07, 0x14};
uchar single_copy_repeat_expected[9] = {
@@ -154,7 +154,7 @@ TEST(GFXTest, CompressionSingleCopyRepeat) {
ElementsAreArray(comp_result.data(), 9));
}
TEST(GFXTest, CompressionSingleOverflowIncrement) {
TEST(LC_LZ2_CompressionTest, CompressionSingleOverflowIncrement) {
ROM rom;
uchar overflow_inc[4] = {0xFE, 0xFF, 0x00, 0x01};
uchar overflow_inc_expected[3] = {BUILD_HEADER(0x03, 0x04), 0xFE, 0xFF};
@@ -163,7 +163,7 @@ TEST(GFXTest, CompressionSingleOverflowIncrement) {
EXPECT_THAT(overflow_inc_expected, ElementsAreArray(comp_result.data(), 3));
}
TEST(GFXTest, CompressionMixedRepeatIncrement) {
TEST(LC_LZ2_CompressionTest, CompressionMixedRepeatIncrement) {
ROM rom;
uchar to_compress_string[28] = {0x05, 0x05, 0x05, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x05, 0x02, 0x05, 0x02,
@@ -183,7 +183,7 @@ TEST(GFXTest, CompressionMixedRepeatIncrement) {
}
*/
TEST(GFXTest, CompressionMixedIncrementIntraCopyOffset) {
TEST(LC_LZ2_CompressionTest, CompressionMixedIncrementIntraCopyOffset) {
ROM rom;
uchar to_compress_string[] = {0x05, 0x05, 0x05, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x05, 0x02, 0x05, 0x02,
@@ -207,7 +207,7 @@ TEST(GFXTest, CompressionMixedIncrementIntraCopyOffset) {
ElementsAreArray(comp_result.data(), 9));
}
TEST(GFXTest, CompressionMixedIncrementIntraCopySource) {
TEST(LC_LZ2_CompressionTest, CompressionMixedIncrementIntraCopySource) {
ROM rom;
uchar to_compress_string[] = {0x05, 0x05, 0x05, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x05, 0x02, 0x05, 0x02,
@@ -236,7 +236,7 @@ TEST(GFXTest, CompressionMixedIncrementIntraCopySource) {
EXPECT_THAT(all_expected, ElementsAreArray(comp_result.data(), 16));
}
TEST(GFXTest, LengthBorderCompression) {
TEST(LC_LZ2_CompressionTest, LengthBorderCompression) {
ROM rom;
uchar buffer[3000];
@@ -270,7 +270,7 @@ TEST(GFXTest, LengthBorderCompression) {
ElementsAreArray(comp_result.data(), 9));
}
TEST(GFXTest, CompressionExtendedWordCopy) {
TEST(LC_LZ2_CompressionTest, CompressionExtendedWordCopy) {
ROM rom;
uchar buffer[3000];
for (unsigned int i = 0; i < 3000; i += 2) {
@@ -286,7 +286,7 @@ TEST(GFXTest, CompressionExtendedWordCopy) {
}
/* Extended Header Command is currently unimplemented
TEST(GFXTest, ExtendedHeaderDecompress) {
TEST(LC_LZ2_CompressionTest, ExtendedHeaderDecompress) {
ROM rom;
Bytes extendedcmd_i = {0b11100100, 0x8F, 0x2A, 0xFF};
uchar extendedcmd_o[50];
@@ -298,7 +298,7 @@ TEST(GFXTest, ExtendedHeaderDecompress) {
ASSERT_THAT(extendedcmd_o, ElementsAreArray(decomp_result.data(), 50));
}
TEST(GFXTest, ExtendedHeaderDecompress2) {
TEST(LC_LZ2_CompressionTest, ExtendedHeaderDecompress2) {
ROM rom;
Bytes extendedcmd_i = {0b11100101, 0x8F, 0x2A, 0xFF};
uchar extendedcmd_o[50];
@@ -313,7 +313,7 @@ TEST(GFXTest, ExtendedHeaderDecompress2) {
}
*/
TEST(GFXTest, CompressionDecompressionEmptyData) {
TEST(LC_LZ2_CompressionTest, CompressionDecompressionEmptyData) {
ROM rom;
uchar empty_input[0] = {};
auto comp_result = ExpectCompressOk(rom, empty_input, 0);
@@ -323,7 +323,7 @@ TEST(GFXTest, CompressionDecompressionEmptyData) {
EXPECT_EQ(0, decomp_result.size());
}
// TEST(GFXTest, CompressionDecompressionSingleByte) {
// TEST(LC_LZ2_CompressionTest, CompressionDecompressionSingleByte) {
// ROM rom;
// uchar single_byte[1] = {0x2A};
// uchar single_byte_expected[3] = {BUILD_HEADER(0x00, 0x01), 0x2A, 0xFF};
@@ -335,7 +335,7 @@ TEST(GFXTest, CompressionDecompressionEmptyData) {
// EXPECT_THAT(single_byte, ElementsAreArray(decomp_result.data(), 1));
// }
// TEST(GFXTest, CompressionDecompressionAllBitsSet) {
// TEST(LC_LZ2_CompressionTest, CompressionDecompressionAllBitsSet) {
// ROM rom;
// uchar all_bits_set[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// uchar all_bits_set_expected[3] = {BUILD_HEADER(0x01, 0x05), 0xFF, 0xFF};
@@ -348,7 +348,7 @@ TEST(GFXTest, CompressionDecompressionEmptyData) {
// EXPECT_THAT(all_bits_set, ElementsAreArray(decomp_result.data(), 5));
// }
// TEST(GFXTest, DecompressionInvalidData) {
// TEST(LC_LZ2_CompressionTest, DecompressionInvalidData) {
// ROM rom;
// Bytes invalid_input = {0xFF, 0xFF}; // Invalid command

View File

@@ -1,12 +0,0 @@
#include "app/rom.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <array>
#include "absl/status/statusor.h"
namespace yaze_test {
namespace rom_test {} // namespace rom_test
} // namespace yaze_test

41
test/snes_palette_test.cc Normal file
View File

@@ -0,0 +1,41 @@
#include "app/gfx/snes_palette.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace yaze_test {
namespace gfx_test {
TEST(SNESColorTest, ConvertRGBtoSNES) {
yaze::app::gfx::snes_color color = {132, 132, 132};
uint16_t snes = yaze::app::gfx::ConvertRGBtoSNES(color);
ASSERT_EQ(snes, 0x4210);
}
TEST(SNESColorTest, ConvertSNEStoRGB) {
uint16_t snes = 0x4210;
yaze::app::gfx::snes_color color = yaze::app::gfx::ConvertSNEStoRGB(snes);
ASSERT_EQ(color.red, 132);
ASSERT_EQ(color.green, 132);
ASSERT_EQ(color.blue, 132);
}
TEST(SNESPaletteTest, AddColor) {
yaze::app::gfx::SNESPalette palette;
yaze::app::gfx::SNESColor color;
palette.AddColor(color);
ASSERT_EQ(palette.size(), 1);
}
TEST(SNESPaletteTest, GetColorOutOfBounds) {
yaze::app::gfx::SNESPalette palette;
std::vector<yaze::app::gfx::SNESColor> colors(5);
palette.Create(colors);
// Now try to get a color at an out-of-bounds index
ASSERT_THROW(palette.GetColor(10), std::exception);
ASSERT_THROW(palette[10], std::exception);
}
} // namespace gfx_test
} // namespace yaze_test