yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
graphics_editor.cc
Go to the documentation of this file.
1// Related header
2#include "graphics_editor.h"
3
4// C++ standard library headers
5#include <algorithm>
6#include <filesystem>
7#include <set>
8
9// Third-party library headers
10#include "absl/status/status.h"
11#include "absl/status/statusor.h"
12#include "absl/strings/str_cat.h"
13#include "imgui/imgui.h"
14#include "imgui/misc/cpp/imgui_stdlib.h"
15
16// Project headers
19#include "app/gfx/core/bitmap.h"
27#include "app/gui/core/color.h"
28#include "app/gui/core/icons.h"
29#include "app/gui/core/input.h"
30#include "app/gui/core/style.h"
34#include "app/platform/window.h"
35#include "core/rom_settings.h"
36#include "rom/rom.h"
37#include "rom/snes.h"
38#include "util/file_util.h"
39#include "util/log.h"
40
41namespace yaze {
42namespace editor {
43
45using ImGui::Button;
46using ImGui::InputInt;
47using ImGui::InputText;
48using ImGui::SameLine;
49
52 return;
53 auto* panel_manager = dependencies_.panel_manager;
54
55 // Initialize panel components
56 sheet_browser_panel_ = std::make_unique<SheetBrowserPanel>(&state_);
57 pixel_editor_panel_ = std::make_unique<PixelEditorPanel>(
59 palette_controls_panel_ = std::make_unique<PaletteControlsPanel>(&state_, rom_);
60 link_sprite_panel_ = std::make_unique<LinkSpritePanel>(&state_, rom_);
61 gfx_group_panel_ = std::make_unique<GfxGroupEditor>();
62 gfx_group_panel_->SetRom(rom_);
63 gfx_group_panel_->SetGameData(game_data_);
64 paletteset_panel_ = std::make_unique<PalettesetEditorPanel>();
65 paletteset_panel_->SetRom(rom_);
66 paletteset_panel_->SetGameData(game_data_);
67
68 sheet_browser_panel_->Initialize();
69 pixel_editor_panel_->Initialize();
70 palette_controls_panel_->Initialize();
71 link_sprite_panel_->Initialize();
72
73 // Register panels using EditorPanel system with callbacks
74 panel_manager->RegisterEditorPanel(
75 std::make_unique<GraphicsSheetBrowserPanel>([this]() {
77 status_ = sheet_browser_panel_->Update();
78 }
79 }));
80
81 panel_manager->RegisterEditorPanel(
82 std::make_unique<GraphicsPixelEditorPanel>([this]() {
84 status_ = pixel_editor_panel_->Update();
85 }
86 }));
87
88 panel_manager->RegisterEditorPanel(
89 std::make_unique<GraphicsPaletteControlsPanel>([this]() {
92 }
93 }));
94
95 panel_manager->RegisterEditorPanel(
96 std::make_unique<GraphicsLinkSpritePanel>([this]() {
98 status_ = link_sprite_panel_->Update();
99 }
100 }));
101
102 panel_manager->RegisterEditorPanel(
103 std::make_unique<GraphicsGfxGroupPanel>([this]() {
104 if (gfx_group_panel_) {
105 status_ = gfx_group_panel_->Update();
106 }
107 }));
108
109 // Paletteset editor panel (separated from GfxGroupEditor for better UX)
110 panel_manager->RegisterEditorPanel(
111 std::make_unique<GraphicsPalettesetPanel>([this]() {
112 if (paletteset_panel_) {
113 status_ = paletteset_panel_->Update();
114 }
115 }));
116
117 // Prototype viewer and polyhedral panels are not registered by default.
118}
119
120absl::Status GraphicsEditor::Load() {
121 gfx::ScopedTimer timer("GraphicsEditor::Load");
122
123 // Initialize all graphics sheets with appropriate palettes from ROM
124 // This ensures textures are created for editing
125 if (rom()->is_loaded()) {
126 auto& sheets = gfx::Arena::Get().gfx_sheets();
127
128 // Apply default palettes to all sheets based on common SNES ROM structure
129 // Sheets 0-112: Use overworld/dungeon palettes
130 // Sheets 113-127: Use sprite palettes
131 // Sheets 128-222: Use auxiliary/menu palettes
132
133 LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets",
135
136 int sheets_queued = 0;
137 for (int i = 0; i < zelda3::kNumGfxSheets; i++) {
138 if (!sheets[i].is_active() || !sheets[i].surface()) {
139 continue; // Skip inactive or surface-less sheets
140 }
141
142 // Palettes are now applied during ROM loading in LoadAllGraphicsData()
143 // Just queue texture creation for sheets that don't have textures yet
144 if (!sheets[i].texture()) {
145 // Fix: Ensure default palettes are applied if missing
146 // This handles the case where sheets are loaded but have no palette assigned
147 if (sheets[i].palette().empty()) {
148 // Default palette assignment logic
149 if (i <= 112) {
150 // Overworld/Dungeon sheets - use Dungeon Main palette (Group 0, Index 0)
151 if (game_data() && game_data()->palette_groups.dungeon_main.size() > 0) {
152 sheets[i].SetPaletteWithTransparent(
153 game_data()->palette_groups.dungeon_main.palette(0), 0);
154 }
155 } else if (i >= 113 && i <= 127) {
156 // Sprite sheets - use Sprites Aux1 palette (Group 4, Index 0)
157 if (game_data() && game_data()->palette_groups.sprites_aux1.size() > 0) {
158 sheets[i].SetPaletteWithTransparent(
159 game_data()->palette_groups.sprites_aux1.palette(0), 0);
160 }
161 } else {
162 // Menu/Aux sheets - use HUD palette if available, or fallback
163 if (game_data() && game_data()->palette_groups.hud.size() > 0) {
164 sheets[i].SetPaletteWithTransparent(
165 game_data()->palette_groups.hud.palette(0), 0);
166 }
167 }
168 }
169
172 sheets_queued++;
173 }
174 }
175
176 LOG_INFO("GraphicsEditor", "Queued texture creation for %d graphics sheets",
177 sheets_queued);
178 }
179
180 return absl::OkStatus();
181}
182
183absl::Status GraphicsEditor::Save() {
184 if (!rom_ || !rom_->is_loaded()) {
185 return absl::FailedPreconditionError("ROM not loaded");
186 }
187
188 // Only save sheets that have been modified
189 if (!state_.HasUnsavedChanges()) {
190 LOG_INFO("GraphicsEditor", "No modified sheets to save");
191 return absl::OkStatus();
192 }
193
194 LOG_INFO("GraphicsEditor", "Saving %zu modified graphics sheets",
195 state_.modified_sheets.size());
196
197 auto& sheets = gfx::Arena::Get().gfx_sheets();
198 std::set<uint16_t> saved_sheets;
199 std::vector<uint16_t> skipped_sheets;
200
201 for (uint16_t sheet_id : state_.modified_sheets) {
202 if (sheet_id >= zelda3::kNumGfxSheets) continue;
203
204 auto& sheet = sheets[sheet_id];
205 if (!sheet.is_active()) continue;
206
207 // Determine BPP and compression based on sheet range
208 int bpp = 3; // Default 3BPP
209 bool compressed = true;
210
211 // Sheets 113-114, 218+ are 2BPP
212 if (sheet_id == 113 || sheet_id == 114 || sheet_id >= 218) {
213 bpp = 2;
214 }
215
216 // Sheets 115-126 are uncompressed
217 if (sheet_id >= 115 && sheet_id <= 126) {
218 compressed = false;
219 }
220
221 if (bpp == 2) {
222 const size_t expected_size =
224 const size_t actual_size = sheet.vector().size();
225 if (actual_size < expected_size) {
226 LOG_WARN(
227 "GraphicsEditor",
228 "Skipping 2BPP sheet %02X save (expected %zu bytes, got %zu)",
229 sheet_id, expected_size, actual_size);
230 skipped_sheets.push_back(sheet_id);
231 continue;
232 }
233 }
234
235 // Calculate ROM offset for this sheet
236 // Get version constants from game_data
237 auto version_constants =
238 zelda3::kVersionConstantsMap.at(game_data()->version);
239 const uint32_t gfx_ptr1 = core::RomSettings::Get().GetAddressOr(
241 version_constants.kOverworldGfxPtr1);
242 const uint32_t gfx_ptr2 = core::RomSettings::Get().GetAddressOr(
244 version_constants.kOverworldGfxPtr2);
245 const uint32_t gfx_ptr3 = core::RomSettings::Get().GetAddressOr(
247 version_constants.kOverworldGfxPtr3);
248 uint32_t offset = zelda3::GetGraphicsAddress(
249 rom_->data(), static_cast<uint8_t>(sheet_id), gfx_ptr1, gfx_ptr2,
250 gfx_ptr3, rom_->size());
251
252 // Convert 8BPP bitmap data to SNES planar format
253 auto snes_tile_data = gfx::IndexedToSnesSheet(sheet.vector(), bpp);
254
255 constexpr size_t kDecompressedSheetSize = 0x800;
256 std::vector<uint8_t> base_data;
257 if (compressed) {
258 auto decomp_result = gfx::lc_lz2::DecompressV2(
259 rom_->data(), offset, static_cast<int>(kDecompressedSheetSize), 1,
260 rom_->size());
261 if (!decomp_result.ok()) {
262 return decomp_result.status();
263 }
264 base_data = std::move(*decomp_result);
265 } else {
266 auto read_result =
267 rom_->ReadByteVector(offset, kDecompressedSheetSize);
268 if (!read_result.ok()) {
269 return read_result.status();
270 }
271 base_data = std::move(*read_result);
272 }
273
274 if (base_data.size() < snes_tile_data.size()) {
275 base_data.resize(snes_tile_data.size(), 0);
276 }
277 std::copy(snes_tile_data.begin(), snes_tile_data.end(),
278 base_data.begin());
279
280 std::vector<uint8_t> final_data;
281 if (compressed) {
282 // Compress using Hyrule Magic LC-LZ2
283 int compressed_size = 0;
284 auto compressed_data = gfx::HyruleMagicCompress(
285 base_data.data(), static_cast<int>(base_data.size()),
286 &compressed_size, 1);
287 final_data.assign(compressed_data.begin(),
288 compressed_data.begin() + compressed_size);
289 } else {
290 final_data = std::move(base_data);
291 }
292
293 // Write data to ROM buffer
294 for (size_t i = 0; i < final_data.size(); i++) {
295 rom_->WriteByte(offset + i, final_data[i]);
296 }
297
298 LOG_INFO("GraphicsEditor", "Saved sheet %02X (%zu bytes, %s) at offset %06X",
299 sheet_id, final_data.size(), compressed ? "compressed" : "raw",
300 offset);
301 saved_sheets.insert(sheet_id);
302 }
303
304 // Clear modified tracking after successful save
305 state_.ClearModifiedSheets(saved_sheets);
306 if (!skipped_sheets.empty()) {
307 return absl::FailedPreconditionError(
308 absl::StrCat("Skipped ", skipped_sheets.size(),
309 " 2BPP sheet(s); full data unavailable."));
310 }
311
312 return absl::OkStatus();
313}
314
316 // Panels are now drawn via PanelManager::DrawAllVisiblePanels()
317 // This Update() only handles editor-level state and keyboard shortcuts
318
319 // Handle editor-level keyboard shortcuts
321
323 return absl::OkStatus();
324}
325
326absl::Status GraphicsEditor::Undo() {
327 return undo_manager_.Undo();
328}
329
330absl::Status GraphicsEditor::Redo() {
331 return undo_manager_.Redo();
332}
333
335 // Skip if ImGui wants keyboard input
336 if (ImGui::GetIO().WantTextInput) {
337 return;
338 }
339
340 // Tool shortcuts (only when graphics editor is active)
341 if (ImGui::IsKeyPressed(ImGuiKey_V, false)) {
343 }
344 if (ImGui::IsKeyPressed(ImGuiKey_B, false)) {
346 }
347 if (ImGui::IsKeyPressed(ImGuiKey_E, false)) {
349 }
350 if (ImGui::IsKeyPressed(ImGuiKey_G, false) && !ImGui::GetIO().KeyCtrl) {
352 }
353 if (ImGui::IsKeyPressed(ImGuiKey_I, false)) {
355 }
356 if (ImGui::IsKeyPressed(ImGuiKey_L, false) && !ImGui::GetIO().KeyCtrl) {
358 }
359 if (ImGui::IsKeyPressed(ImGuiKey_R, false) && !ImGui::GetIO().KeyCtrl) {
361 }
362
363 // Zoom shortcuts
364 if (ImGui::IsKeyPressed(ImGuiKey_Equal, false) ||
365 ImGui::IsKeyPressed(ImGuiKey_KeypadAdd, false)) {
366 state_.ZoomIn();
367 }
368 if (ImGui::IsKeyPressed(ImGuiKey_Minus, false) ||
369 ImGui::IsKeyPressed(ImGuiKey_KeypadSubtract, false)) {
370 state_.ZoomOut();
371 }
372
373 // Grid toggle (Ctrl+G)
374 if (ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_G, false)) {
376 }
377
378 // Sheet navigation
379 if (ImGui::IsKeyPressed(ImGuiKey_PageDown, false)) {
380 NextSheet();
381 }
382 if (ImGui::IsKeyPressed(ImGuiKey_PageUp, false)) {
383 PrevSheet();
384 }
385}
386
389 ImGui::Begin("Memory Editor", &open_memory_editor_);
391 ImGui::End();
392 }
393
394 constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
395 ImGuiTableFlags_Resizable |
396 ImGuiTableFlags_SizingStretchSame;
397
398 BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags)
399 SETUP_COLUMN("File Import (BIN, CGX, ROM)")
400 SETUP_COLUMN("Palette (COL)")
401 ImGui::TableSetupColumn("Tilemaps and Objects (SCR, PNL, OBJ)",
402 ImGuiTableColumnFlags_WidthFixed);
403 SETUP_COLUMN("Graphics Preview")
405 NEXT_COLUMN() {
410 }
411
412 NEXT_COLUMN() {
414 }
415
418 scr_loaded_, false, 0);
420
422 if (super_donkey_) {
423 // Super Donkey prototype graphics
424 for (size_t i = 0; i < num_sheets_to_load_ && i < gfx_sheets_.size(); i++) {
425 if (gfx_sheets_[i].is_active() && gfx_sheets_[i].texture()) {
426 ImGui::Image((ImTextureID)(intptr_t)gfx_sheets_[i].texture(),
427 ImVec2(128, 32));
428 if ((i + 1) % 4 != 0) {
429 ImGui::SameLine();
430 }
431 }
432 }
433 } else if (cgx_loaded_ && col_file_) {
434 // Load the CGX graphics
436 cgx_loaded_, true, 5);
437 } else {
438 // Load the BIN/Clipboard Graphics
440 gfx_loaded_, true, 2);
441 }
442 END_TABLE()
443}
444
445// =============================================================================
446// Prototype Viewer Import Methods
447// =============================================================================
448
450 gui::TextWithSeparators("Cgx Import");
451 InputInt("BPP", &current_bpp_);
452
453 InputText("##CGXFile", &cgx_file_name_);
454 SameLine();
455
456 if (ImGui::Button("Open CGX")) {
458 cgx_file_name_ = filename;
459 cgx_file_path_ = std::filesystem::absolute(filename).string();
460 is_open_ = true;
461 cgx_loaded_ = true;
462 }
463
464 if (ImGui::Button("Copy CGX Path")) {
465 ImGui::SetClipboardText(cgx_file_path_.c_str());
466 }
467
468 if (ImGui::Button("Load CGX Data")) {
471
472 cgx_bitmap_.Create(0x80, 0x200, 8, decoded_cgx_);
473 if (col_file_) {
477 }
478 }
479
480 return absl::OkStatus();
481}
482
484 InputText("##ScrFile", &scr_file_name_);
485
486 if (ImGui::Button("Open SCR")) {
488 scr_file_name_ = filename;
489 scr_file_path_ = std::filesystem::absolute(filename).string();
490 is_open_ = true;
491 scr_loaded_ = true;
492 }
493
494 InputInt("SCR Mod", &scr_mod_value_);
495
496 if (ImGui::Button("Load Scr Data")) {
498
499 decoded_scr_data_.resize(0x100 * 0x100);
502
503 scr_bitmap_.Create(0x100, 0x100, 8, decoded_scr_data_);
504 if (scr_loaded_) {
508 }
509 }
510
511 return absl::OkStatus();
512}
513
515 gui::TextWithSeparators("COL Import");
516 InputText("##ColFile", &col_file_name_);
517 SameLine();
518
519 if (ImGui::Button("Open COL")) {
521 col_file_name_ = filename;
522 col_file_path_ = std::filesystem::absolute(filename).string();
524 auto col_data_ = gfx::GetColFileData(temp_rom_.mutable_data());
525 if (col_file_palette_group_.size() != 0) {
527 }
528 auto col_file_palette_group_status =
530 if (col_file_palette_group_status.ok()) {
531 col_file_palette_group_ = col_file_palette_group_status.value();
532 }
534
535 // gigaleak dev format based code
537 col_file_ = true;
538 is_open_ = true;
539 }
540 HOVER_HINT(".COL, .BAK");
541
542 if (ImGui::Button("Copy Col Path")) {
543 ImGui::SetClipboardText(col_file_path_.c_str());
544 }
545
546 if (rom()->is_loaded()) {
547 gui::TextWithSeparators("ROM Palette");
548 gui::InputHex("Palette Index", &current_palette_index_);
549 ImGui::Combo("Palette", &current_palette_, kPaletteGroupAddressesKeys,
550 IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
551 }
552
553 if (col_file_palette_.size() != 0) {
556 }
557
558 return absl::OkStatus();
559}
560
562 gui::TextWithSeparators("OBJ Import");
563
564 InputText("##ObjFile", &obj_file_path_);
565 SameLine();
566
567 if (ImGui::Button("Open OBJ")) {
569 obj_file_path_ = std::filesystem::absolute(filename).string();
571 is_open_ = true;
572 obj_loaded_ = true;
573 }
574 HOVER_HINT(".OBJ, .BAK");
575
576 return absl::OkStatus();
577}
578
580 gui::TextWithSeparators("Tilemap Import");
581
582 InputText("##TMapFile", &tilemap_file_path_);
583 SameLine();
584
585 if (ImGui::Button("Open Tilemap")) {
587 tilemap_file_path_ = std::filesystem::absolute(filename).string();
590
591 // Extract the high and low bytes from the file.
592 auto decomp_sheet = gfx::lc_lz2::DecompressV2(tilemap_rom_.data(), 0, 0x800,
595 tilemap_loaded_ = true;
596 is_open_ = true;
597 }
598 HOVER_HINT(".DAT, .BIN, .HEX");
599
600 return absl::OkStatus();
601}
602
604 gui::TextWithSeparators("BIN Import");
605
606 InputText("##ROMFile", &file_path_);
607 SameLine();
608
609 if (ImGui::Button("Open BIN")) {
611 file_path_ = filename;
613 is_open_ = true;
614 }
615 HOVER_HINT(".BIN, .HEX");
616
617 if (Button("Copy File Path")) {
618 ImGui::SetClipboardText(file_path_.c_str());
619 }
620
621 gui::InputHex("BIN Offset", &current_offset_);
622 gui::InputHex("BIN Size", &bin_size_);
623
624 if (Button("Decompress BIN")) {
625 if (file_path_.empty()) {
626 return absl::InvalidArgumentError(
627 "Please select a file before decompressing.");
628 }
630 }
631
632 return absl::OkStatus();
633}
634
636 gui::TextWithSeparators("Clipboard Import");
637 if (Button("Paste From Clipboard")) {
638 const char* text = ImGui::GetClipboardText();
639 if (text) {
640 const auto clipboard_data =
641 std::vector<uint8_t>(text, text + strlen(text));
642 ImGui::MemFree((void*)text);
643 status_ = temp_rom_.LoadFromData(clipboard_data);
644 is_open_ = true;
645 open_memory_editor_ = true;
646 }
647 }
650 gui::InputHex("Num Sheets", &num_sheets_to_load_);
651
652 if (Button("Decompress Clipboard Data")) {
653 if (temp_rom_.is_loaded()) {
654 status_ = DecompressImportData(0x40000);
655 } else {
656 status_ = absl::InvalidArgumentError(
657 "Please paste data into the clipboard before "
658 "decompressing.");
659 }
660 }
661
662 return absl::OkStatus();
663}
664
666 gui::TextWithSeparators("Experimental");
667 if (Button("Decompress Super Donkey Full")) {
668 if (file_path_.empty()) {
669 return absl::InvalidArgumentError(
670 "Please select `super_donkey_1.bin` before "
671 "importing.");
672 }
674 }
675 ImGui::SetItemTooltip(
676 "Requires `super_donkey_1.bin` to be imported under the "
677 "BIN import section.");
678 return absl::OkStatus();
679}
680
682 std::string title = "Memory Editor";
683 if (is_open_) {
684 static yaze::gui::MemoryEditorWidget mem_edit;
685 mem_edit.DrawWindow(title.c_str(), temp_rom_.mutable_data(),
686 temp_rom_.size());
687 }
688 return absl::OkStatus();
689}
690
693 temp_rom_.data(), current_offset_, size, 1,
694 temp_rom_.size()));
695
696 auto converted_sheet = gfx::SnesTo8bppSheet(import_data_, 3);
698 converted_sheet);
699
700 if (rom()->is_loaded() && game_data()) {
701 auto palette_group = game_data()->palette_groups.overworld_animated;
702 z3_rom_palette_ = palette_group[current_palette_];
703 if (col_file_) {
705 } else {
707 }
708 }
709
711 &bin_bitmap_);
712 gfx_loaded_ = true;
713
714 return absl::OkStatus();
715}
716
718 int i = 0;
719 for (const auto& offset : kSuperDonkeyTiles) {
720 int offset_value =
721 std::stoi(offset, nullptr, 16); // convert hex string to int
723 auto decompressed_data,
724 gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000, 1,
725 temp_rom_.size()));
726 auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
728 gfx::kTilesheetDepth, converted_sheet);
729 if (col_file_) {
730 gfx_sheets_[i].SetPalette(
732 } else {
733 // ROM palette
734 if (!game_data()) {
735 return absl::FailedPreconditionError("GameData not available");
736 }
737 auto palette_group = game_data()->palette_groups.get_group(
738 kPaletteGroupAddressesKeys[current_palette_]);
739 z3_rom_palette_ = palette_group->palette(current_palette_index_);
740 gfx_sheets_[i].SetPalette(z3_rom_palette_);
741 }
742
745 i++;
746 }
747
748 for (const auto& offset : kSuperDonkeySprites) {
749 int offset_value =
750 std::stoi(offset, nullptr, 16); // convert hex string to int
752 auto decompressed_data,
753 gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000, 1,
754 temp_rom_.size()));
755 auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
757 gfx::kTilesheetDepth, converted_sheet);
758 if (col_file_) {
759 gfx_sheets_[i].SetPalette(
761 } else {
762 // ROM palette
763 if (game_data()) {
764 auto palette_group = game_data()->palette_groups.get_group(
765 kPaletteGroupAddressesKeys[current_palette_]);
766 z3_rom_palette_ = palette_group->palette(current_palette_index_);
767 gfx_sheets_[i].SetPalette(z3_rom_palette_);
768 }
769 }
770
773 i++;
774 }
775 super_donkey_ = true;
777
778 return absl::OkStatus();
779}
780
786
792
793void GraphicsEditor::SelectSheet(uint16_t sheet_id) {
794 if (sheet_id >= zelda3::kNumGfxSheets) {
795 return;
796 }
797 state_.SelectSheet(sheet_id);
798}
799
800void GraphicsEditor::HighlightTile(uint16_t sheet_id, uint16_t tile_index,
801 const std::string& label,
802 double duration_secs) {
803 if (sheet_id >= zelda3::kNumGfxSheets) {
804 return;
805 }
806 state_.HighlightTile(sheet_id, tile_index, label, duration_secs);
807}
808
809} // namespace editor
810} // namespace yaze
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:431
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:155
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:476
auto mutable_data()
Definition rom.h:140
auto data() const
Definition rom.h:139
auto size() const
Definition rom.h:138
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:255
bool is_loaded() const
Definition rom.h:132
static RomSettings & Get()
uint32_t GetAddressOr(const std::string &key, uint32_t default_value) const
UndoManager undo_manager_
Definition editor.h:307
zelda3::GameData * game_data() const
Definition editor.h:297
EditorDependencies dependencies_
Definition editor.h:306
void HighlightTile(uint16_t sheet_id, uint16_t tile_index, const std::string &label="", double duration_secs=3.0)
Highlight a tile in the current sheet for quick visual focus.
bool HasUnsavedChanges() const
Check if any sheets have unsaved changes.
void SelectSheet(uint16_t sheet_id)
Select a sheet for editing.
void SetTool(PixelTool tool)
Set the current editing tool.
void ClearModifiedSheets()
Clear modification tracking (after save)
std::vector< uint8_t > scr_data_
absl::Status Save() override
void HighlightTile(uint16_t sheet_id, uint16_t tile_index, const std::string &label="", double duration_secs=3.0)
gfx::PaletteGroup col_file_palette_group_
void SelectSheet(uint16_t sheet_id)
absl::Status Load() override
std::unique_ptr< GfxGroupEditor > gfx_group_panel_
std::unique_ptr< PaletteControlsPanel > palette_controls_panel_
std::vector< uint8_t > decoded_cgx_
std::vector< uint8_t > cgx_data_
std::unique_ptr< PixelEditorPanel > pixel_editor_panel_
absl::Status Redo() override
std::unique_ptr< PalettesetEditorPanel > paletteset_panel_
std::vector< uint8_t > import_data_
std::vector< SDL_Color > decoded_col_
absl::Status Undo() override
absl::Status Update() override
std::vector< uint8_t > extra_cgx_data_
std::array< gfx::Bitmap, zelda3::kNumGfxSheets > gfx_sheets_
std::vector< uint8_t > decoded_scr_data_
std::unique_ptr< LinkSpritePanel > link_sprite_panel_
absl::Status DecompressImportData(int size)
std::unique_ptr< SheetBrowserPanel > sheet_browser_panel_
absl::Status Redo()
Redo the top action. Returns error if stack is empty.
absl::Status Undo()
Undo the top action. Returns error if stack is empty.
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:36
std::array< gfx::Bitmap, 223 > & gfx_sheets()
Get reference to all graphics sheets.
Definition arena.h:152
static Arena & Get()
Definition arena.cc:21
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
Definition bitmap.cc:201
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
Definition bitmap.cc:384
RAII timer for automatic timing management.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
#define LOG_WARN(category, format,...)
Definition log.h:107
#define LOG_INFO(category, format,...)
Definition log.h:105
#define SETUP_COLUMN(l)
Definition macro.h:12
#define END_TABLE()
Definition macro.h:20
#define TABLE_HEADERS()
Definition macro.h:14
#define BEGIN_TABLE(l, n, f)
Definition macro.h:11
#define NEXT_COLUMN()
Definition macro.h:18
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
#define CLEAR_AND_RETURN_STATUS(status)
Definition macro.h:97
#define HOVER_HINT(string)
Definition macro.h:24
constexpr char kOverworldGfxPtr3[]
constexpr char kOverworldGfxPtr1[]
constexpr char kOverworldGfxPtr2[]
const std::string kSuperDonkeySprites[]
const std::string kSuperDonkeyTiles[]
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uint8_t *data, int offset, int size, int mode, size_t rom_size)
Decompresses a buffer of data using the LC_LZ2 algorithm.
constexpr int kNintendoMode1
Definition compression.h:54
absl::Status LoadScr(std::string_view filename, uint8_t input_value, std::vector< uint8_t > &map_data)
Load Scr file (screen data)
std::vector< SDL_Color > DecodeColFile(const std::string_view filename)
Decode color file.
constexpr int kTilesheetHeight
Definition snes_tile.h:17
constexpr int kTilesheetWidth
Definition snes_tile.h:16
absl::Status LoadCgx(uint8_t bpp, std::string_view filename, std::vector< uint8_t > &cgx_data, std::vector< uint8_t > &cgx_loaded, std::vector< uint8_t > &cgx_header)
Load Cgx file (graphical content)
constexpr const char * kPaletteGroupAddressesKeys[]
absl::Status DrawScrWithCgx(uint8_t bpp, std::vector< uint8_t > &map_bitmap_data, std::vector< uint8_t > &map_data, std::vector< uint8_t > &cgx_loaded)
Draw screen tilemap with graphical data.
constexpr int kTilesheetDepth
Definition snes_tile.h:18
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:132
std::vector< uint8_t > IndexedToSnesSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:203
std::vector< uint8_t > HyruleMagicCompress(uint8_t const *const src, int const oldsize, int *const size, int const flag)
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromColFile(std::vector< SnesColor > &palette_rows)
std::vector< SnesColor > GetColFileData(uint8_t *data)
Definition snes_color.cc:89
void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id)
Definition canvas.cc:1751
bool InputHex(const char *label, uint64_t *data)
Definition input.cc:325
void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics, gfx::SnesPalette &palette)
Definition color.cc:312
void TextWithSeparators(const absl::string_view &text)
Definition style.cc:1315
constexpr uint32_t kNumGfxSheets
Definition game_data.h:25
uint32_t GetGraphicsAddress(const uint8_t *data, uint8_t addr, uint32_t ptr1, uint32_t ptr2, uint32_t ptr3, size_t rom_size)
Gets the graphics address for a sheet index.
Definition game_data.cc:112
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
PaletteGroup * get_group(const std::string &group_name)
void DrawWindow(const char *title, void *mem_data, size_t mem_size, size_t base_display_addr=0x0000)
gfx::PaletteGroupMap palette_groups
Definition game_data.h:89