Files
yaze/src/app/gfx/snes_palette.h

363 lines
10 KiB
C++

#ifndef YAZE_APP_GFX_PALETTE_H
#define YAZE_APP_GFX_PALETTE_H
#include <SDL.h>
#include <imgui/imgui.h>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <vector>
#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 {
/**
* @brief Primitive of a SNES color palette.
*/
struct snes_palette {
uint id; /**< ID of the palette. */
uint size; /**< Size of the palette. */
snes_color* colors; /**< Pointer to the colors in the palette. */
};
using snes_palette = struct snes_palette;
uint32_t GetPaletteAddress(const std::string& group_name, size_t palette_index,
size_t color_index);
/**
* @brief Represents a palette of colors for the Super Nintendo Entertainment
* System (SNES).
*
* The `SnesPalette` class provides functionality to create, modify, and access
* colors in an SNES palette. It supports various constructors to initialize the
* palette with different types of data. The palette can be modified by adding
* or changing colors, and it can be cleared to remove all colors. Colors in the
* palette can be accessed using index-based access or through the `GetColor`
* method. The class also provides a method to create a sub-palette by selecting
* a range of colors from the original palette.
*/
class SnesPalette {
public:
template <typename T>
explicit SnesPalette(const std::vector<T>& data) {
for (const auto& item : data) {
colors.push_back(SnesColor(item));
}
size_ = data.size();
}
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>&);
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_++;
}
void AddColor(snes_color color) {
colors.emplace_back(color);
size_++;
}
absl::StatusOr<SnesColor> GetColor(int i) const {
if (i > size_) {
return absl::InvalidArgumentError("SnesPalette: Index out of bounds");
}
return colors[i];
}
auto mutable_color(int i) { 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];
}
return colors[i];
}
void operator()(int i, const SnesColor& color) {
if (i >= size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
}
colors[i] = color;
}
void operator()(int i, const ImVec4& color) {
if (i >= size_) {
throw std::out_of_range("SNESPalette: Index out of bounds");
}
colors[i].set_rgb(color);
colors[i].set_modified(true);
}
SnesPalette sub_palette(int start, int end) const {
SnesPalette pal;
for (int i = start; i < end; i++) {
pal.AddColor(colors[i]);
}
return pal;
}
private:
int size_ = 0; /**< The size of the palette. */
std::vector<SnesColor> colors; /**< The colors in the palette. */
};
SnesPalette ReadPaletteFromRom(int offset, int num_colors, const uint8_t* rom);
std::array<float, 4> ToFloatArray(const SnesColor& color);
/**
* @brief Represents a group of palettes.
*
* Supports adding palettes and colors, clearing the group, and accessing
* palettes and colors by index.
*/
struct PaletteGroup {
PaletteGroup() = default;
explicit PaletteGroup(uint8_t mSize);
absl::Status AddPalette(SnesPalette pal) {
palettes.emplace_back(pal);
size_ = palettes.size();
return absl::OkStatus();
}
absl::Status AddColor(SnesColor color) {
if (size_ == 0) {
palettes.emplace_back();
}
palettes[0].AddColor(color);
return absl::OkStatus();
}
void Clear() {
palettes.clear();
size_ = 0;
}
auto name() const { return name_; }
auto size() const { return palettes.size(); }
auto mutable_palette(int i) { return &palettes[i]; }
auto palette(int i) const { return palettes[i]; }
SnesPalette operator[](int i) {
if (i > size_) {
std::cout << "PaletteGroup: Index out of bounds" << std::endl;
return palettes[0];
}
return palettes[i];
}
const SnesPalette& operator[](int i) const {
if (i > size_) {
std::cout << "PaletteGroup: Index out of bounds" << std::endl;
return palettes[0];
}
return palettes[i];
}
absl::Status operator()(int i, const SnesColor& color) {
if (i >= size_) {
return absl::InvalidArgumentError("PaletteGroup: Index out of bounds");
}
palettes[i](0, color);
return absl::OkStatus();
}
absl::Status operator()(int i, const ImVec4& color) {
if (i >= size_) {
return absl::InvalidArgumentError("PaletteGroup: Index out of bounds");
}
palettes[i](0, color);
return absl::OkStatus();
}
private:
int size_ = 0;
std::string name_;
std::vector<SnesPalette> palettes;
};
/**
* @brief Represents a mapping of palette groups.
*
* Originally, this was an actual std::unordered_map but since the palette
* groups supported never change, it was changed to a struct with a method to
* get the group by name.
*/
struct PaletteGroupMap {
PaletteGroup overworld_main;
PaletteGroup overworld_aux;
PaletteGroup overworld_animated;
PaletteGroup hud;
PaletteGroup global_sprites;
PaletteGroup armors;
PaletteGroup swords;
PaletteGroup shields;
PaletteGroup sprites_aux1;
PaletteGroup sprites_aux2;
PaletteGroup sprites_aux3;
PaletteGroup dungeon_main;
PaletteGroup grass;
PaletteGroup object_3d;
PaletteGroup overworld_mini_map;
auto get_group(const std::string& group_name) {
if (group_name == "ow_main") {
return &overworld_main;
} else if (group_name == "ow_aux") {
return &overworld_aux;
} else if (group_name == "ow_animated") {
return &overworld_animated;
} else if (group_name == "hud") {
return &hud;
} else if (group_name == "global_sprites") {
return &global_sprites;
} else if (group_name == "armors") {
return &armors;
} else if (group_name == "swords") {
return &swords;
} else if (group_name == "shields") {
return &shields;
} else if (group_name == "sprites_aux1") {
return &sprites_aux1;
} else if (group_name == "sprites_aux2") {
return &sprites_aux2;
} else if (group_name == "sprites_aux3") {
return &sprites_aux3;
} else if (group_name == "dungeon_main") {
return &dungeon_main;
} else if (group_name == "grass") {
return &grass;
} else if (group_name == "3d_object") {
return &object_3d;
} else if (group_name == "ow_mini_map") {
return &overworld_mini_map;
} else {
throw std::out_of_range("PaletteGroupMap: Group not found");
}
}
template <typename Func>
void for_each(Func&& func) {
func(overworld_main);
func(overworld_aux);
func(overworld_animated);
func(hud);
func(global_sprites);
func(armors);
func(swords);
func(shields);
func(sprites_aux1);
func(sprites_aux2);
func(sprites_aux3);
func(dungeon_main);
func(grass);
func(object_3d);
func(overworld_mini_map);
}
};
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromColFile(
std::vector<SnesColor>& colors);
absl::StatusOr<PaletteGroup> CreatePaletteGroupFromLargePalette(
SnesPalette& palette);
/**
* @brief Loads all the palettes for the game.
*
* This function loads all the palettes for the game, including overworld,
* HUD, armor, swords, shields, sprites, dungeon, grass, and 3D object
* palettes. It also adds the loaded palettes to their respective palette
* groups.
*
*/
absl::Status LoadAllPalettes(const Bytes& rom_data, PaletteGroupMap& groups);
/**
* @brief Represents a set of palettes used in a SNES graphics system.
*/
struct Paletteset {
/**
* @brief Default constructor for Paletteset.
*/
Paletteset() = default;
/**
* @brief Constructor for Paletteset.
* @param main The main palette.
* @param animated The animated palette.
* @param aux1 The first auxiliary palette.
* @param aux2 The second auxiliary palette.
* @param background The background color.
* @param hud The HUD palette.
* @param spr The sprite palette.
* @param spr2 The second sprite palette.
* @param comp The composite palette.
*/
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; /**< The main palette. */
gfx::SnesPalette animated; /**< The animated palette. */
gfx::SnesPalette aux1; /**< The first auxiliary palette. */
gfx::SnesPalette aux2; /**< The second auxiliary palette. */
gfx::SnesColor background; /**< The background color. */
gfx::SnesPalette hud; /**< The HUD palette. */
gfx::SnesPalette spr; /**< The sprite palette. */
gfx::SnesPalette spr2; /**< The second sprite palette. */
gfx::SnesPalette composite; /**< The composite palette. */
};
} // namespace gfx
} // namespace app
} // namespace yaze
#endif // YAZE_APP_GFX_PALETTE_H