5#include "absl/strings/str_format.h"
23 const char* group_names[] = {
24 "ow_main",
"ow_aux",
"ow_animated",
"hud",
"global_sprites",
25 "armors",
"swords",
"shields",
"sprites_aux1",
"sprites_aux2",
26 "sprites_aux3",
"dungeon_main",
"grass",
"3d_object",
"ow_mini_map"
29 for (
const auto& group_name : group_names) {
31 auto* group = palette_groups->get_group(group_name);
33 std::vector<SnesPalette> originals;
34 for (
size_t i = 0; i < group->size(); i++) {
35 originals.push_back(group->palette(i));
39 }
catch (
const std::exception& e) {
55 int color_index)
const {
56 const auto* group =
GetGroup(group_name);
57 if (!group || palette_index < 0 || palette_index >= group->size()) {
61 const auto& palette = group->palette_ref(palette_index);
62 if (color_index < 0 || color_index >= palette.size()) {
66 return palette[color_index];
70 int palette_index,
int color_index,
73 return absl::FailedPreconditionError(
"PaletteManager not initialized");
78 return absl::NotFoundError(
79 absl::StrFormat(
"Palette group '%s' not found", group_name));
82 if (palette_index < 0 || palette_index >= group->size()) {
83 return absl::InvalidArgumentError(
84 absl::StrFormat(
"Palette index %d out of range [0, %d)", palette_index,
88 auto* palette = group->mutable_palette(palette_index);
89 if (color_index < 0 || color_index >= palette->size()) {
90 return absl::InvalidArgumentError(
91 absl::StrFormat(
"Color index %d out of range [0, %d)", color_index,
96 SnesColor original_color = (*palette)[color_index];
99 (*palette)[color_index] = new_color;
106 auto now = std::chrono::system_clock::now();
107 auto timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
108 now.time_since_epoch())
112 original_color, new_color,
113 static_cast<uint64_t
>(timestamp_ms)};
118 group_name, palette_index, color_index};
122 auto now = std::chrono::system_clock::now();
123 auto timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
124 now.time_since_epoch())
127 {group_name, palette_index, color_index, original_color, new_color,
128 static_cast<uint64_t
>(timestamp_ms)});
131 return absl::OkStatus();
135 int palette_index,
int color_index) {
137 return SetColor(group_name, palette_index, color_index, original);
143 return absl::FailedPreconditionError(
"PaletteManager not initialized");
149 palette_index >= it->second.size()) {
150 return absl::NotFoundError(
"Original palette not found");
154 if (!group || palette_index >= group->size()) {
155 return absl::NotFoundError(
"Palette group or index not found");
159 *group->mutable_palette(palette_index) = it->second[palette_index];
167 group_name, palette_index, -1};
170 return absl::OkStatus();
180 std::vector<std::string> groups;
182 groups.push_back(group_name);
193 int palette_index)
const {
198 return it->second.contains(palette_index);
203 int color_index)
const {
209 auto pal_it = group_it->second.find(palette_index);
210 if (pal_it == group_it->second.end()) {
214 return pal_it->second.contains(color_index);
220 for (
const auto& [__, color_set] : palette_map) {
221 count += color_set.size();
231 return absl::FailedPreconditionError(
"PaletteManager not initialized");
236 return absl::NotFoundError(
237 absl::StrFormat(
"Palette group '%s' not found", group_name));
244 return absl::OkStatus();
248 for (
int palette_idx : pal_it->second) {
249 auto* palette = group->mutable_palette(palette_idx);
254 for (
int color_idx : color_it->second) {
266 for (
size_t i = 0; i < group->size() && i < originals.size(); i++) {
267 originals[i] = group->palette(i);
281 return absl::OkStatus();
286 return absl::FailedPreconditionError(
"PaletteManager not initialized");
298 return absl::OkStatus();
320 for (
int palette_idx : pal_it->second) {
321 if (palette_idx < orig_it->second.size()) {
322 *group->mutable_palette(palette_idx) = orig_it->second[palette_idx];
367 if (group && change.palette_index < group->size()) {
368 auto* palette = group->mutable_palette(change.palette_index);
369 if (change.color_index < palette->size()) {
370 (*palette)[change.color_index] = change.original_color;
394 if (group && change.palette_index < group->size()) {
395 auto* palette = group->mutable_palette(change.palette_index);
396 if (change.color_index < palette->size()) {
397 (*palette)[change.color_index] = change.new_color;
468 }
catch (
const std::exception&) {
474 const std::string& group_name)
const {
480 return const_cast<Rom*
>(
rom_)->mutable_palette_group()->get_group(
482 }
catch (
const std::exception&) {
489 int color_index)
const {
495 const auto& palette = it->second[palette_index];
496 if (color_index >= palette.size()) {
500 return palette[color_index];
522 int palette_index,
int color_index) {
The Rom class is used to load, save, and modify Rom data.
auto mutable_palette_group()
void set_dirty(bool dirty)
absl::Status WriteShort(int addr, uint16_t value)
void RecordChange(const PaletteColorChange &change)
Helper: Record a change for undo.
absl::Status SetColor(const std::string &group_name, int palette_index, int color_index, const SnesColor &new_color)
Set a color in a palette (records change for undo)
std::vector< std::string > GetModifiedGroups() const
Get list of modified palette group names.
static constexpr size_t kMaxUndoHistory
bool HasUnsavedChanges() const
Check if there are ANY unsaved changes.
bool IsGroupModified(const std::string &group_name) const
Check if a specific palette group has modifications.
absl::Status SaveGroup(const std::string &group_name)
Save a specific palette group to ROM.
void BeginBatch()
Begin a batch operation (groups multiple changes into one undo step)
PaletteGroup * GetMutableGroup(const std::string &group_name)
Helper: Get mutable palette group.
void Undo()
Undo the most recent change.
void ClearHistory()
Clear undo/redo history.
std::unordered_map< int, ChangeCallback > change_listeners_
Change listeners.
int batch_depth_
Batch operation support.
std::deque< PaletteColorChange > redo_stack_
std::unordered_map< std::string, std::unordered_set< int > > modified_palettes_
void UnregisterChangeListener(int callback_id)
Unregister a change listener.
Rom * rom_
ROM instance (not owned)
std::unordered_map< std::string, std::unordered_map< int, std::unordered_set< int > > > modified_colors_
bool CanRedo() const
Check if redo is available.
bool InBatch() const
Check if currently in a batch operation.
bool CanUndo() const
Check if undo is available.
absl::Status ResetColor(const std::string &group_name, int palette_index, int color_index)
Reset a single color to its original ROM value.
void NotifyListeners(const PaletteChangeEvent &event)
Helper: Notify all listeners of an event.
void ClearModifiedFlags(const std::string &group_name)
Helper: Clear modified flags for a group.
void EndBatch()
End a batch operation.
int RegisterChangeListener(ChangeCallback callback)
Register a callback for palette change events.
std::deque< PaletteColorChange > undo_stack_
Undo/redo stacks.
void Initialize(Rom *rom)
Initialize the palette manager with ROM data.
absl::Status ResetPalette(const std::string &group_name, int palette_index)
Reset an entire palette to original ROM values.
SnesColor GetOriginalColor(const std::string &group_name, int palette_index, int color_index) const
Helper: Get original color from snapshot.
bool IsColorModified(const std::string &group_name, int palette_index, int color_index) const
Check if a specific color is modified.
void MarkModified(const std::string &group_name, int palette_index, int color_index)
Helper: Mark a color as modified.
void DiscardGroup(const std::string &group_name)
Discard changes for a specific group.
bool IsInitialized() const
Check if manager is initialized.
void DiscardAllChanges()
Discard ALL unsaved changes.
size_t GetModifiedColorCount() const
Get count of modified colors across all groups.
std::unordered_map< std::string, std::vector< SnesPalette > > original_palettes_
std::vector< PaletteColorChange > batch_changes_
const PaletteGroup * GetGroup(const std::string &group_name) const
Helper: Get const palette group.
SnesColor GetColor(const std::string &group_name, int palette_index, int color_index) const
Get a color from a palette.
std::function< void(const PaletteChangeEvent &)> ChangeCallback
absl::Status SaveAllToRom()
Save ALL modified palettes to ROM.
bool IsPaletteModified(const std::string &group_name, int palette_index) const
Check if a specific palette is modified.
void Redo()
Redo the most recently undone change.
#define RETURN_IF_ERROR(expression)
uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index)
Main namespace for the application.
Event notification for palette changes.
@ kColorChanged
Single color was modified.
@ kPaletteReset
Entire palette was reset.
@ kAllDiscarded
All changes discarded.
@ kGroupDiscarded
Palette group changes were discarded.
@ kAllSaved
All changes saved to ROM.
@ kGroupSaved
Palette group was saved to ROM.
Represents a single color change operation.
Represents a group of palettes.