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
232 // ========== Persistence ==========
233
237 absl::Status SaveGroup(const std::string& group_name);
238
242 absl::Status SaveAllToRom();
243
244 // Checkpoint persistence metadata that SaveGroup/SaveAllToRom clear. This is
245 // used by the coordinated ROM-save pipeline so a later serializer,
246 // validation gate, backup, or disk failure leaves palette edits retryable.
247 absl::Status BeginSaveTransaction();
250
254 void DiscardGroup(const std::string& group_name);
255
259 void DiscardAllChanges();
260
261 // ========== Preview Mode ==========
262
270 absl::Status ApplyPreviewChanges();
271
272 // ========== Undo/Redo ==========
273
277 void Undo();
278
282 void Redo();
283
287 bool CanUndo() const;
288
292 bool CanRedo() const;
293
297 size_t GetUndoStackSize() const;
298
302 size_t GetRedoStackSize() const;
303
307 void ClearHistory();
308
309 // ========== Change Notifications ==========
310
316
320 void UnregisterChangeListener(int callback_id);
321
322 // ========== Batch Operations ==========
323
328 void BeginBatch();
329
333 void EndBatch();
334
338 bool InBatch() const;
339
340 private:
341 PaletteManager() = default;
342 ~PaletteManager() = default;
343
345 PaletteGroup* GetMutableGroup(const std::string& group_name);
346
348 const PaletteGroup* GetGroup(const std::string& group_name) const;
349
351 SnesColor GetOriginalColor(const std::string& group_name, int palette_index,
352 int color_index) const;
353
355 void RecordChange(const PaletteColorChange& change);
356
358 void NotifyListeners(const PaletteChangeEvent& event);
359
361 void MarkModified(const std::string& group_name, int palette_index,
362 int color_index);
363
365 void ClearModifiedFlags(const std::string& group_name);
366
368 std::unordered_map<std::string, std::vector<SnesPalette>> original_palettes;
369 std::unordered_map<std::string, std::unordered_set<int>> modified_palettes;
370 std::unordered_map<std::string,
371 std::unordered_map<int, std::unordered_set<int>>>
373 };
374
376 bool initialized = false;
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 std::optional<SaveTransactionSnapshot> save_transaction_snapshot;
383 std::deque<PaletteColorChange> undo_stack;
384 std::deque<PaletteColorChange> redo_stack;
385 int batch_depth = 0;
386 std::vector<PaletteColorChange> batch_changes;
387 };
388
390 const SessionState* CurrentState() const;
391 const SessionState* FindState(const zelda3::GameData* game_data) const;
392
393 // ========== Member Variables ==========
394
397
399 Rom* rom_ = nullptr;
400
402 std::unordered_map<const zelda3::GameData*, SessionState> session_states_;
403
406
407 static constexpr size_t kMaxUndoHistory = 500;
408
410 std::unordered_map<int, ChangeCallback> change_listeners_;
412};
413
414} // namespace gfx
415} // namespace yaze
416
417#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.
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