yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
palette_manager.h
Go to the documentation of this file.
1#ifndef YAZE_APP_GFX_PALETTE_MANAGER_H
2#define YAZE_APP_GFX_PALETTE_MANAGER_H
3
4#include <cstdint>
5#include <deque>
6#include <functional>
7#include <memory>
8#include <optional>
9#include <string>
10#include <unordered_map>
11#include <unordered_set>
12#include <utility>
13#include <vector>
14
15#include "absl/status/status.h"
16#include "absl/status/statusor.h"
19
20namespace yaze {
21
22// Forward declarations
23class Rom;
24namespace zelda3 {
25struct GameData;
26}
27
28namespace gfx {
29
41
54
56 std::string group_name;
57 int palette_index = -1;
58 int color_index = -1;
59};
60
77 public:
78 using ChangeCallback = std::function<void(const PaletteChangeEvent&)>;
79
81 static PaletteManager& Get() {
82 static PaletteManager instance;
83 return instance;
84 }
85
86 // Delete copy/move constructors and assignment operators
91
92 // ========== Initialization ==========
93
98 void Initialize(zelda3::GameData* game_data);
99
104 void Initialize(Rom* rom);
105
109 bool IsInitialized() const;
110
117 void ActivateSession(zelda3::GameData* game_data);
118
125 bool IsSessionActive(const zelda3::GameData* game_data) const;
126
130 bool IsManaging(const zelda3::GameData* game_data) const;
131
135 void ReleaseSession(const zelda3::GameData* game_data);
136
140 void ResetForTesting();
141
142 // ========== Color Operations ==========
143
151 SnesColor GetColor(const std::string& group_name, int palette_index,
152 int color_index) const;
153
162 absl::Status SetColor(const std::string& group_name, int palette_index,
163 int color_index, const SnesColor& new_color);
164
168 absl::Status ResetColor(const std::string& group_name, int palette_index,
169 int color_index);
170
174 absl::Status ResetPalette(const std::string& group_name, int palette_index);
175
176 // ========== Dirty Tracking ==========
177
181 bool HasUnsavedChanges() const;
182
186 bool HasUnsavedChanges(const zelda3::GameData* game_data) const;
187
191 std::vector<std::string> GetModifiedGroups() const;
192
196 bool IsGroupModified(const std::string& group_name) const;
197
201 bool IsPaletteModified(const std::string& group_name,
202 int palette_index) const;
203
207 bool IsColorModified(const std::string& group_name, int palette_index,
208 int color_index) const;
209
213 size_t GetModifiedColorCount() const;
214
218 size_t GetModifiedColorCount(const zelda3::GameData* game_data) const;
219
223 std::vector<std::pair<uint32_t, uint32_t>> GetModifiedColorWriteRanges()
224 const;
225
229 std::vector<std::pair<uint32_t, uint32_t>> GetModifiedColorWriteRanges(
230 const zelda3::GameData* game_data) const;
231
238 std::vector<std::pair<uint32_t, uint32_t>> GetModifiedGroupColorWriteRanges(
239 const std::string& group_name) const;
240
241 // ========== Persistence ==========
242
246 absl::Status SaveGroup(const std::string& group_name);
247
251 absl::Status SaveAllToRom();
252
253 // Checkpoint persistence metadata that SaveGroup/SaveAllToRom clear. This is
254 // used by the coordinated ROM-save pipeline so a later serializer,
255 // validation gate, backup, or disk failure leaves palette edits retryable.
256 absl::Status BeginSaveTransaction();
259
263 void DiscardGroup(const std::string& group_name);
264
268 void DiscardAllChanges();
269
270 // ========== Preview Mode ==========
271
279 absl::Status ApplyPreviewChanges();
280
281 // ========== Undo/Redo ==========
282
286 void Undo();
287
291 void Redo();
292
296 bool CanUndo() const;
297
301 bool CanRedo() const;
302
306 size_t GetUndoStackSize() const;
307
311 size_t GetRedoStackSize() const;
312
316 void ClearHistory();
317
318 // ========== Change Notifications ==========
319
325
329 void UnregisterChangeListener(int callback_id);
330
331 // ========== Batch Operations ==========
332
337 void BeginBatch();
338
342 void EndBatch();
343
347 bool InBatch() const;
348
349 private:
350 PaletteManager() = default;
351 ~PaletteManager() = default;
352
354 PaletteGroup* GetMutableGroup(const std::string& group_name);
355
357 const PaletteGroup* GetGroup(const std::string& group_name) const;
358
360 SnesColor GetOriginalColor(const std::string& group_name, int palette_index,
361 int color_index) const;
362
364 void RecordChange(const PaletteColorChange& change);
365
367 void NotifyListeners(const PaletteChangeEvent& event);
368
370 void MarkModified(const std::string& group_name, int palette_index,
371 int color_index);
372
374 void ClearModifiedFlags(const std::string& group_name);
375
377 std::unordered_map<std::string, std::vector<SnesPalette>> original_palettes;
378 std::unordered_map<std::string, std::unordered_set<int>> modified_palettes;
379 std::unordered_map<std::string,
380 std::unordered_map<int, std::unordered_set<int>>>
382 };
383
385 bool initialized = false;
386 std::unordered_map<std::string, std::vector<SnesPalette>> original_palettes;
387 std::unordered_map<std::string, std::unordered_set<int>> modified_palettes;
388 std::unordered_map<std::string,
389 std::unordered_map<int, std::unordered_set<int>>>
391 std::optional<SaveTransactionSnapshot> save_transaction_snapshot;
392 std::deque<PaletteColorChange> undo_stack;
393 std::deque<PaletteColorChange> redo_stack;
394 int batch_depth = 0;
395 std::vector<PaletteColorChange> batch_changes;
396 };
397
399 const SessionState* CurrentState() const;
400 const SessionState* FindState(const zelda3::GameData* game_data) const;
401
402 // ========== Member Variables ==========
403
406
408 Rom* rom_ = nullptr;
409
411 std::unordered_map<const zelda3::GameData*, SessionState> session_states_;
412
415
416 static constexpr size_t kMaxUndoHistory = 500;
417
419 std::unordered_map<int, ChangeCallback> change_listeners_;
421};
422
423} // namespace gfx
424} // namespace yaze
425
426#endif // YAZE_APP_GFX_PALETTE_MANAGER_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
Centralized palette management system.
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.
std::vector< std::pair< uint32_t, uint32_t > > GetModifiedColorWriteRanges() const
Get exact, coalesced half-open ROM ranges for modified colors.
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 ActivateSession(zelda3::GameData *game_data)
Select the palette state for a ROM session without resnapshotting it.
size_t GetUndoStackSize() const
Get size of undo stack.
void Undo()
Undo the most recent change.
size_t GetRedoStackSize() const
Get size of redo stack.
void ClearHistory()
Clear undo/redo history.
std::unordered_map< int, ChangeCallback > change_listeners_
Change listeners.
std::vector< std::pair< uint32_t, uint32_t > > GetModifiedGroupColorWriteRanges(const std::string &group_name) const
Get exact, coalesced half-open ROM ranges for one modified group.
void UnregisterChangeListener(int callback_id)
Unregister a change listener.
Rom * rom_
ROM instance (not owned) - legacy, used when game_data_ is null.
bool IsManaging(const zelda3::GameData *game_data) const
Check whether the manager is bound to this exact GameData and ROM.
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.
void Initialize(zelda3::GameData *game_data)
Initialize the palette manager with GameData.
void ResetForTesting()
Reset all state for test isolation.
absl::Status ResetColor(const std::string &group_name, int palette_index, int color_index)
Reset a single color to its original ROM value.
const SessionState * FindState(const zelda3::GameData *game_data) const
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::unordered_map< const zelda3::GameData *, SessionState > session_states_
Per-GameData state. RomSession owns the keys and releases them on teardown.
SessionState unbound_state_
State used only before a GameData session is selected (legacy/tests).
PaletteManager(PaletteManager &&)=delete
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.
PaletteManager & operator=(const PaletteManager &)=delete
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.
zelda3::GameData * game_data_
GameData instance (not owned) - preferred.
void DiscardAllChanges()
Discard ALL unsaved changes.
size_t GetModifiedColorCount() const
Get count of modified colors across all groups.
PaletteManager & operator=(PaletteManager &&)=delete
static PaletteManager & Get()
Get the singleton instance.
PaletteManager(const PaletteManager &)=delete
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
SessionState * CurrentState()
absl::Status SaveAllToRom()
Save ALL modified palettes to ROM.
absl::Status BeginSaveTransaction()
bool IsPaletteModified(const std::string &group_name, int palette_index) const
Check if a specific palette is modified.
absl::Status ApplyPreviewChanges()
Apply preview changes to other editors without saving to ROM.
void Redo()
Redo the most recently undone change.
bool IsSessionActive(const zelda3::GameData *game_data) const
Check whether this exact GameData is the active palette session.
void ReleaseSession(const zelda3::GameData *game_data)
Forget all palette tracking for a closing or reloaded ROM session.
SNES Color container.
Definition snes_color.h:110
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.
SnesColor new_color
New color after change.
int color_index
Index of color within palette.
std::string group_name
Palette group name (e.g., "ow_main")
int palette_index
Index of palette within group.
uint64_t timestamp_ms
Timestamp in milliseconds.
SnesColor original_color
Original color before change.
Represents a group of palettes.
std::unordered_map< std::string, std::unordered_map< int, std::unordered_set< int > > > modified_colors
std::unordered_map< std::string, std::vector< SnesPalette > > original_palettes
std::unordered_map< std::string, std::unordered_set< int > > modified_palettes
std::vector< PaletteColorChange > batch_changes
std::unordered_map< std::string, std::unordered_map< int, std::unordered_set< int > > > modified_colors
std::unordered_map< std::string, std::vector< SnesPalette > > original_palettes
std::optional< SaveTransactionSnapshot > save_transaction_snapshot
std::deque< PaletteColorChange > redo_stack
std::unordered_map< std::string, std::unordered_set< int > > modified_palettes
std::deque< PaletteColorChange > undo_stack