14#include "absl/status/status.h"
15#include "absl/status/statusor.h"
16#include "absl/strings/str_format.h"
18#include "imgui/imgui.h"
24 assert((
sizeof(data) % 4 == 0) && (
sizeof(data) <= 32));
25 for (
unsigned i = 0; i <
sizeof(data); i += 2) {
27 col.
set_snes(
static_cast<uint8_t
>(data[i + 1]) << 8);
28 col.
set_snes(col.
snes() |
static_cast<uint8_t
>(data[i]));
34 assert((
sizeof(snes_pal) % 4 == 0) && (
sizeof(snes_pal) <= 32));
35 for (
unsigned i = 0; i <
sizeof(snes_pal); i += 2) {
37 col.
set_snes(snes_pal[i + 1] << (uint16_t)8);
45 uint16_t color = (
static_cast<uint8_t
>(data[i + 1]) << 8) |
46 static_cast<uint8_t
>(data[i]);
52 for (
const auto& color : colors) {
60 for (
const auto& color : colors) {
68 for (
const auto& color : colors) {
79namespace palette_group_internal {
82 auto data = rom_data.data();
83 size_t rom_size = rom_data.size();
84 for (
int i = 0; i < 6; i++) {
88 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
89 return absl::OutOfRangeError(absl::StrFormat(
90 "Overworld main palette %d out of bounds: offset %d, size %zu", i,
96 return absl::OkStatus();
100 const std::vector<uint8_t>& rom_data,
102 auto data = rom_data.data();
103 size_t rom_size = rom_data.size();
104 for (
int i = 0; i < 20; i++) {
107 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
108 return absl::OutOfRangeError(absl::StrFormat(
109 "Overworld aux palette %d out of bounds: offset %d, size %zu", i,
115 return absl::OkStatus();
119 const std::vector<uint8_t>& rom_data,
121 auto data = rom_data.data();
122 size_t rom_size = rom_data.size();
123 for (
int i = 0; i < 14; i++) {
126 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
127 return absl::OutOfRangeError(absl::StrFormat(
128 "Overworld animated palette %d out of bounds: offset %d, size %zu", i,
134 return absl::OkStatus();
139 auto data = rom_data.data();
140 size_t rom_size = rom_data.size();
141 for (
int i = 0; i < 2; i++) {
144 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
145 return absl::OutOfRangeError(
146 absl::StrFormat(
"HUD palette %d out of bounds: offset %d, size %zu",
147 i, offset, rom_size));
152 return absl::OkStatus();
157 auto data = rom_data.data();
158 size_t rom_size = rom_data.size();
162 int num_colors1 = 60;
163 if (offset1 < 0 || offset1 + (num_colors1 * 2) >
static_cast<int>(rom_size)) {
164 return absl::OutOfRangeError(absl::StrFormat(
165 "Global sprite LW palette out of bounds: offset %d, size %zu", offset1,
173 int num_colors2 = 60;
174 if (offset2 < 0 || offset2 + (num_colors2 * 2) >
static_cast<int>(rom_size)) {
175 return absl::OutOfRangeError(absl::StrFormat(
176 "Global sprite DW palette out of bounds: offset %d, size %zu", offset2,
181 return absl::OkStatus();
186 auto data = rom_data.data();
187 size_t rom_size = rom_data.size();
188 for (
int i = 0; i < 5; i++) {
191 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
192 return absl::OutOfRangeError(
193 absl::StrFormat(
"Armor palette %d out of bounds: offset %d, size %zu",
194 i, offset, rom_size));
199 return absl::OkStatus();
204 auto data = rom_data.data();
205 size_t rom_size = rom_data.size();
206 for (
int i = 0; i < 4; i++) {
209 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
210 return absl::OutOfRangeError(
211 absl::StrFormat(
"Sword palette %d out of bounds: offset %d, size %zu",
212 i, offset, rom_size));
217 return absl::OkStatus();
222 auto data = rom_data.data();
223 size_t rom_size = rom_data.size();
224 for (
int i = 0; i < 3; i++) {
227 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
228 return absl::OutOfRangeError(absl::StrFormat(
229 "Shield palette %d out of bounds: offset %d, size %zu", i, offset,
235 return absl::OkStatus();
240 auto data = rom_data.data();
241 size_t rom_size = rom_data.size();
242 for (
int i = 0; i < 12; i++) {
245 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
246 return absl::OutOfRangeError(absl::StrFormat(
247 "Sprite aux1 palette %d out of bounds: offset %d, size %zu", i,
253 return absl::OkStatus();
258 auto data = rom_data.data();
259 size_t rom_size = rom_data.size();
260 for (
int i = 0; i < 11; i++) {
263 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
264 return absl::OutOfRangeError(absl::StrFormat(
265 "Sprite aux2 palette %d out of bounds: offset %d, size %zu", i,
271 return absl::OkStatus();
276 auto data = rom_data.data();
277 size_t rom_size = rom_data.size();
278 for (
int i = 0; i < 24; i++) {
281 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
282 return absl::OutOfRangeError(absl::StrFormat(
283 "Sprite aux3 palette %d out of bounds: offset %d, size %zu", i,
289 return absl::OkStatus();
294 auto data = rom_data.data();
295 size_t rom_size = rom_data.size();
296 for (
int i = 0; i < 20; i++) {
299 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
300 return absl::OutOfRangeError(absl::StrFormat(
301 "Dungeon main palette %d out of bounds: offset %d, size %zu", i,
307 return absl::OkStatus();
312 size_t rom_size = rom_data.size();
317 return absl::OutOfRangeError(
318 absl::StrFormat(
"Grass LW color out of bounds: offset %d, size %zu",
326 return absl::OutOfRangeError(
327 absl::StrFormat(
"Grass DW color out of bounds: offset %d, size %zu",
335 return absl::OutOfRangeError(absl::StrFormat(
336 "Grass special color out of bounds: offset %d, size %zu",
341 return absl::OkStatus();
346 auto data = rom_data.data();
347 size_t rom_size = rom_data.size();
351 if (offset1 < 0 || offset1 + (num_colors1 * 2) >
static_cast<int>(rom_size)) {
352 return absl::OutOfRangeError(
353 absl::StrFormat(
"Triforce palette out of bounds: offset %d, size %zu",
361 if (offset2 < 0 || offset2 + (num_colors2 * 2) >
static_cast<int>(rom_size)) {
362 return absl::OutOfRangeError(
363 absl::StrFormat(
"Crystal palette out of bounds: offset %d, size %zu",
368 return absl::OkStatus();
372 const std::vector<uint8_t>& rom_data,
374 auto data = rom_data.data();
375 size_t rom_size = rom_data.size();
376 for (
int i = 0; i < 2; i++) {
378 int num_colors = 128;
379 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
380 return absl::OutOfRangeError(absl::StrFormat(
381 "Overworld minimap palette %d out of bounds: offset %d, size %zu", i,
387 return absl::OkStatus();
391constexpr std::array<std::pair<absl::string_view, uint32_t>, 15>
410constexpr std::array<std::pair<absl::string_view, uint32_t>, 15>
416 {
"global_sprites", 60},
423 {
"dungeon_main", 90},
426 {
"ow_mini_map", 128},
431 absl::string_view group_name,
432 const std::array<std::pair<absl::string_view, uint32_t>, N>& table) {
433 for (
const auto& [name, value] : table) {
434 if (name == group_name) {
438 throw std::out_of_range(
439 absl::StrFormat(
"Unknown palette group: %s", group_name));
443 size_t color_index) {
445 const uint32_t base_address =
447 const uint32_t colors_per_palette =
451 uint32_t address = base_address + (palette_index * colors_per_palette * 2) +
484 int color_offset = 0;
485 std::vector<gfx::SnesColor> colors(num_colors);
487 while (color_offset < num_colors) {
494 uint16_t snes_color_word = (uint16_t)((rom[offset + 1]) << 8) | rom[offset];
498 new_color.
red = (snes_color_word & 0x1F) * 8;
499 new_color.
green = ((snes_color_word >> 5) & 0x1F) * 8;
500 new_color.
blue = ((snes_color_word >> 10) & 0x1F) * 8;
517 std::array<float, 4> colorArray;
518 colorArray[0] = color.
rgb().x / 255.0f;
519 colorArray[1] = color.
rgb().y / 255.0f;
520 colorArray[2] = color.
rgb().z / 255.0f;
521 colorArray[3] = color.
rgb().w;
526 std::vector<SnesColor>& palette_rows) {
528 for (
int i = 0; i < palette_rows.size(); i += 8) {
530 for (
int j = 0; j < 8; j++) {
531 palette.
AddColor(palette_rows[i + j]);
535 return palette_group;
556 for (
int i = 0; i < palette.
size(); i += num_colors) {
558 if (i + num_colors <= palette.
size()) {
559 for (
int j = 0; j < num_colors; j++) {
560 auto color = palette[i + j];
568 return palette_group;
571using namespace palette_group_internal;
591 return absl::OkStatus();
static std::unordered_map< uint8_t, gfx::Paletteset > palettesets_
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
void set_snes(uint16_t val)
Set color from SNES 15-bit format.
constexpr uint16_t snes() const
Get SNES 15-bit color.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void AddColor(const SnesColor &color)
static constexpr size_t kMaxColors
absl::Status LoadDungeonMainPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldMiniMapPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux2Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldMainPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux1Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadGlobalSpritePalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldAnimatedPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadArmorPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadGrassColors(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSpriteAux3Palettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadHUDPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadShieldPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadOverworldAuxiliaryPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status Load3DObjectPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
absl::Status LoadSwordPalettes(const std::vector< uint8_t > &rom_data, gfx::PaletteGroupMap &palette_groups)
Contains classes for handling graphical data.
constexpr int kHardcodedGrassSpecial
constexpr int kHudPalettes
constexpr int kOverworldPaletteAux
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t *rom)
Read a palette from ROM data.
uint32_t LookupPaletteGroupValue(absl::string_view group_name, const std::array< std::pair< absl::string_view, uint32_t >, N > &table)
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromLargePalette(SnesPalette &palette, int num_colors)
Create a PaletteGroup by dividing a large palette into sub-palettes.
constexpr int kHardcodedGrassLW
constexpr int kArmorPalettes
constexpr std::array< std::pair< absl::string_view, uint32_t >, 15 > kPaletteGroupAddressMap
constexpr int kCrystalPalette
uint16_t ConvertRgbToSnes(const snes_color &color)
Convert RGB (0-255) to SNES 15-bit color.
constexpr int kShieldPalettes
constexpr int kSpritesPalettesAux2
constexpr int kOverworldPaletteAnimated
SnesColor ReadColorFromRom(int offset, const uint8_t *rom)
constexpr int kOverworldMiniMapPalettes
constexpr int kOverworldPaletteMain
constexpr int kSwordPalettes
constexpr int kHardcodedGrassDW
constexpr int kGlobalSpritesLW
constexpr int kSpritesPalettesAux1
constexpr std::array< std::pair< absl::string_view, uint32_t >, 15 > kPaletteGroupColorCounts
std::array< float, 4 > ToFloatArray(const SnesColor &color)
constexpr int kGlobalSpritePalettesDW
constexpr int kSpritesPalettesAux3
constexpr int kDungeonMainPalettes
uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index)
constexpr int kTriforcePalette
absl::Status LoadAllPalettes(const std::vector< uint8_t > &rom_data, PaletteGroupMap &groups)
Loads all the palettes for the game.
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromColFile(std::vector< SnesColor > &palette_rows)
SDL2/SDL3 compatibility layer.
#define RETURN_IF_ERROR(expr)
SNES color in 15-bit RGB format (BGR555)
Represents a mapping of palette groups.
PaletteGroup overworld_main
PaletteGroup overworld_aux
PaletteGroup overworld_mini_map
PaletteGroup sprites_aux1
PaletteGroup sprites_aux2
PaletteGroup overworld_animated
PaletteGroup sprites_aux3
PaletteGroup dungeon_main
PaletteGroup global_sprites
Represents a group of palettes.
void AddColor(SnesColor color)
void AddPalette(SnesPalette pal)