#include "snes_palette.h" #include #include #include #include #include #include #include #include #include "absl/container/flat_hash_map.h" // for flat_hash_map #include "absl/status/status.h" // for Status #include "app/core/constants.h" namespace yaze { namespace app { namespace gfx { // Define a hash map to hold the addresses of different palette groups const absl::flat_hash_map paletteGroupAddresses = { {"ow_main", core::overworldPaletteMain}, {"ow_aux", core::overworldPaletteAuxialiary}, {"ow_animated", core::overworldPaletteAnimated}, {"hud", core::hudPalettes}, {"global_sprites", core::globalSpritePalettesLW}, {"armors", core::armorPalettes}, {"swords", core::swordPalettes}, {"shields", core::shieldPalettes}, {"sprites_aux1", core::spritePalettesAux1}, {"sprites_aux2", core::spritePalettesAux2}, {"sprites_aux3", core::spritePalettesAux3}, {"dungeon_main", core::dungeonMainPalettes}, {"grass", core::hardcodedGrassLW}, {"3d_object", core::triforcePalette}, {"ow_mini_map", core::overworldMiniMapPalettes}, }; // Define a hash map to hold the number of colors in each palette group const absl::flat_hash_map paletteGroupColorCounts = { {"ow_main", 35}, {"ow_aux", 21}, {"ow_animated", 7}, {"hud", 32}, {"global_sprites", 60}, {"armors", 15}, {"swords", 3}, {"shields", 4}, {"sprites_aux1", 7}, {"sprites_aux2", 7}, {"sprites_aux3", 7}, {"dungeon_main", 90}, {"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; } 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 Extract(const char* data, unsigned int offset, unsigned int palette_size) { std::vector palette(palette_size); for (unsigned int i = 0; i < palette_size * 2; i += 2) { uint16_t snes_color = (static_cast(data[offset + i + 1]) << 8) | static_cast(data[offset + i]); palette[i / 2] = ConvertSNEStoRGB(snes_color); } return palette; } std::vector Convert(const std::vector& palette) { std::vector 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 GetColFileData(uchar* data) { std::vector 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(data[i + 1]) << 8); col.SetSNES(col.GetSNES() | static_cast(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& cols) { for (const auto& each : cols) { SNESColor scol; scol.SetRGB(each); colors.push_back(scol); } size_ = cols.size(); } SNESPalette::SNESPalette(const std::vector& cols) { for (const auto& each : cols) { SNESColor scol; scol.SetSNES(ConvertRGBtoSNES(each)); colors.push_back(scol); } size_ = cols.size(); } SNESPalette::SNESPalette(const std::vector& 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->ncolors = size_; auto color = std::vector(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 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); // Retrieve the number of colors for each palette in the group uint32_t colors_per_palette = paletteGroupColorCounts.at(group_name); // Calculate the address for thes specified color in the ROM uint32_t address = base_address + (palette_index * colors_per_palette * 2) + (color_index * 2); return address; } std::array ToFloatArray(const SNESColor& color) { std::array 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( std::vector& palette_rows) { PaletteGroup toret; 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].GetRomRGB()); } 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) { PaletteGroup toret; std::cout << "Palette size is " << palette.size() << std::endl; for (int i = 0; i < palette.size(); i += 8) { 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 toret; } } // namespace gfx } // namespace app } // namespace yaze