10#include "absl/container/flat_hash_map.h"
11#include "absl/status/status.h"
12#include "absl/status/statusor.h"
14#include "imgui/imgui.h"
20 assert((
sizeof(data) % 4 == 0) && (
sizeof(data) <= 32));
21 for (
unsigned i = 0; i <
sizeof(data); i += 2) {
23 col.
set_snes(
static_cast<uint8_t
>(data[i + 1]) << 8);
24 col.
set_snes(col.
snes() |
static_cast<uint8_t
>(data[i]));
32 assert((
sizeof(snes_pal) % 4 == 0) && (
sizeof(snes_pal) <= 32));
33 for (
unsigned i = 0; i <
sizeof(snes_pal); i += 2) {
35 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(
90 absl::StrFormat(
"Overworld main palette %d out of bounds: offset %d, size %zu",
91 i, offset, rom_size));
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(
109 absl::StrFormat(
"Overworld aux palette %d out of bounds: offset %d, size %zu",
110 i, offset, rom_size));
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(
128 absl::StrFormat(
"Overworld animated palette %d out of bounds: offset %d, size %zu",
129 i, offset, rom_size));
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));
151 return absl::OkStatus();
156 auto data = rom_data.data();
157 size_t rom_size = rom_data.size();
161 int num_colors1 = 60;
162 if (offset1 < 0 || offset1 + (num_colors1 * 2) >
static_cast<int>(rom_size)) {
163 return absl::OutOfRangeError(
164 absl::StrFormat(
"Global sprite LW palette out of bounds: offset %d, size %zu",
172 int num_colors2 = 60;
173 if (offset2 < 0 || offset2 + (num_colors2 * 2) >
static_cast<int>(rom_size)) {
174 return absl::OutOfRangeError(
175 absl::StrFormat(
"Global sprite DW palette out of bounds: offset %d, size %zu",
180 return absl::OkStatus();
185 auto data = rom_data.data();
186 size_t rom_size = rom_data.size();
187 for (
int i = 0; i < 5; i++) {
190 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
191 return absl::OutOfRangeError(
192 absl::StrFormat(
"Armor palette %d out of bounds: offset %d, size %zu",
193 i, offset, rom_size));
197 return absl::OkStatus();
202 auto data = rom_data.data();
203 size_t rom_size = rom_data.size();
204 for (
int i = 0; i < 4; i++) {
207 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
208 return absl::OutOfRangeError(
209 absl::StrFormat(
"Sword palette %d out of bounds: offset %d, size %zu",
210 i, offset, rom_size));
214 return absl::OkStatus();
219 auto data = rom_data.data();
220 size_t rom_size = rom_data.size();
221 for (
int i = 0; i < 3; i++) {
224 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
225 return absl::OutOfRangeError(
226 absl::StrFormat(
"Shield palette %d out of bounds: offset %d, size %zu",
227 i, offset, rom_size));
231 return absl::OkStatus();
236 auto data = rom_data.data();
237 size_t rom_size = rom_data.size();
238 for (
int i = 0; i < 12; i++) {
241 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
242 return absl::OutOfRangeError(
243 absl::StrFormat(
"Sprite aux1 palette %d out of bounds: offset %d, size %zu",
244 i, offset, rom_size));
248 return absl::OkStatus();
253 auto data = rom_data.data();
254 size_t rom_size = rom_data.size();
255 for (
int i = 0; i < 11; i++) {
258 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
259 return absl::OutOfRangeError(
260 absl::StrFormat(
"Sprite aux2 palette %d out of bounds: offset %d, size %zu",
261 i, offset, rom_size));
265 return absl::OkStatus();
270 auto data = rom_data.data();
271 size_t rom_size = rom_data.size();
272 for (
int i = 0; i < 24; i++) {
275 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
276 return absl::OutOfRangeError(
277 absl::StrFormat(
"Sprite aux3 palette %d out of bounds: offset %d, size %zu",
278 i, offset, rom_size));
282 return absl::OkStatus();
287 auto data = rom_data.data();
288 size_t rom_size = rom_data.size();
289 for (
int i = 0; i < 20; i++) {
292 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
293 return absl::OutOfRangeError(
294 absl::StrFormat(
"Dungeon main palette %d out of bounds: offset %d, size %zu",
295 i, offset, rom_size));
299 return absl::OkStatus();
304 size_t rom_size = rom_data.size();
307 if (kHardcodedGrassLW < 0 || kHardcodedGrassLW + 2 >
static_cast<int>(rom_size)) {
308 return absl::OutOfRangeError(
309 absl::StrFormat(
"Grass LW color out of bounds: offset %d, size %zu",
315 if (kHardcodedGrassDW < 0 || kHardcodedGrassDW + 2 >
static_cast<int>(rom_size)) {
316 return absl::OutOfRangeError(
317 absl::StrFormat(
"Grass DW color out of bounds: offset %d, size %zu",
323 if (kHardcodedGrassSpecial < 0 || kHardcodedGrassSpecial + 2 >
static_cast<int>(rom_size)) {
324 return absl::OutOfRangeError(
325 absl::StrFormat(
"Grass special color out of bounds: offset %d, size %zu",
330 return absl::OkStatus();
335 auto data = rom_data.data();
336 size_t rom_size = rom_data.size();
340 if (offset1 < 0 || offset1 + (num_colors1 * 2) >
static_cast<int>(rom_size)) {
341 return absl::OutOfRangeError(
342 absl::StrFormat(
"Triforce palette out of bounds: offset %d, size %zu",
350 if (offset2 < 0 || offset2 + (num_colors2 * 2) >
static_cast<int>(rom_size)) {
351 return absl::OutOfRangeError(
352 absl::StrFormat(
"Crystal palette out of bounds: offset %d, size %zu",
357 return absl::OkStatus();
361 const std::vector<uint8_t>& rom_data,
363 auto data = rom_data.data();
364 size_t rom_size = rom_data.size();
365 for (
int i = 0; i < 2; i++) {
367 int num_colors = 128;
368 if (offset < 0 || offset + (num_colors * 2) >
static_cast<int>(rom_size)) {
369 return absl::OutOfRangeError(
370 absl::StrFormat(
"Overworld minimap palette %d out of bounds: offset %d, size %zu",
371 i, offset, rom_size));
376 return absl::OkStatus();
399 {
"ow_main", 35}, {
"ow_aux", 21}, {
"ow_animated", 7},
400 {
"hud", 32}, {
"global_sprites", 60}, {
"armors", 15},
401 {
"swords", 3}, {
"shields", 4}, {
"sprites_aux1", 7},
402 {
"sprites_aux2", 7}, {
"sprites_aux3", 7}, {
"dungeon_main", 90},
403 {
"grass", 1}, {
"3d_object", 8}, {
"ow_mini_map", 128},
407 size_t color_index) {
415 uint32_t address = base_address + (palette_index * colors_per_palette * 2) +
448 int color_offset = 0;
449 std::vector<gfx::SnesColor> colors(num_colors);
451 while (color_offset < num_colors) {
458 uint16_t snes_color_word = (uint16_t)((rom[offset + 1]) << 8) | rom[offset];
462 new_color.
red = (snes_color_word & 0x1F) * 8;
463 new_color.
green = ((snes_color_word >> 5) & 0x1F) * 8;
464 new_color.
blue = ((snes_color_word >> 10) & 0x1F) * 8;
481 std::array<float, 4> colorArray;
482 colorArray[0] = color.
rgb().x / 255.0f;
483 colorArray[1] = color.
rgb().y / 255.0f;
484 colorArray[2] = color.
rgb().z / 255.0f;
485 colorArray[3] = color.
rgb().w;
490 std::vector<SnesColor>& palette_rows) {
492 for (
int i = 0; i < palette_rows.size(); i += 8) {
494 for (
int j = 0; j < 8; j++) {
495 palette.
AddColor(palette_rows[i + j]);
499 return palette_group;
520 for (
int i = 0; i < palette.
size(); i += num_colors) {
522 if (i + num_colors <= palette.
size()) {
523 for (
int j = 0; j < num_colors; j++) {
524 auto color = palette[i + j];
532 return palette_group;
535using namespace palette_group_internal;
555 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.
void set_rgb(const ImVec4 val)
Set color from ImVec4 (0.0-1.0 range)
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
snes_color ConvertSnesToRgb(uint16_t color_snes)
Convert SNES 15-bit color to RGB (0-255 range)
constexpr int kHudPalettes
constexpr int kOverworldPaletteAux
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t *rom)
Read a palette from ROM data.
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 int kCrystalPalette
const absl::flat_hash_map< std::string, uint32_t > kPaletteGroupAddressMap
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
const absl::flat_hash_map< std::string, uint32_t > kPaletteGroupColorCounts
constexpr int kSpritesPalettesAux1
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)