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 "rom/rom.h"
36#include "rom/snes.h"
37#include "util/file_util.h"
38#include "util/log.h"
39
40namespace yaze {
41namespace editor {
42
44using ImGui::Button;
45using ImGui::InputInt;
46using ImGui::InputText;
47using ImGui::SameLine;
48
51 return;
52 auto* panel_manager = dependencies_.panel_manager;
53
54 // Initialize panel components
55 sheet_browser_panel_ = std::make_unique<SheetBrowserPanel>(&state_);
56 pixel_editor_panel_ = std::make_unique<PixelEditorPanel>(&state_, rom_);
57 palette_controls_panel_ = std::make_unique<PaletteControlsPanel>(&state_, rom_);
58 link_sprite_panel_ = std::make_unique<LinkSpritePanel>(&state_, rom_);
59 polyhedral_panel_ = std::make_unique<PolyhedralEditorPanel>(rom_);
60 gfx_group_panel_ = std::make_unique<GfxGroupEditor>();
61 gfx_group_panel_->SetRom(rom_);
62 gfx_group_panel_->SetGameData(game_data_);
63 paletteset_panel_ = std::make_unique<PalettesetEditorPanel>();
64 paletteset_panel_->SetRom(rom_);
65 paletteset_panel_->SetGameData(game_data_);
66
67 sheet_browser_panel_->Initialize();
68 pixel_editor_panel_->Initialize();
69 palette_controls_panel_->Initialize();
70 link_sprite_panel_->Initialize();
71
72 // Register panels using EditorPanel system with callbacks
73 panel_manager->RegisterEditorPanel(
74 std::make_unique<GraphicsSheetBrowserPanel>([this]() {
76 status_ = sheet_browser_panel_->Update();
77 }
78 }));
79
80 panel_manager->RegisterEditorPanel(
81 std::make_unique<GraphicsPixelEditorPanel>([this]() {
83 status_ = pixel_editor_panel_->Update();
84 }
85 }));
86
87 panel_manager->RegisterEditorPanel(
88 std::make_unique<GraphicsPaletteControlsPanel>([this]() {
91 }
92 }));
93
94 panel_manager->RegisterEditorPanel(
95 std::make_unique<GraphicsLinkSpritePanel>([this]() {
97 status_ = link_sprite_panel_->Update();
98 }
99 }));
100
101 panel_manager->RegisterEditorPanel(
102 std::make_unique<GraphicsPolyhedralPanel>([this]() {
103 if (polyhedral_panel_) {
104 status_ = polyhedral_panel_->Update();
105 }
106 }));
107
108 panel_manager->RegisterEditorPanel(
109 std::make_unique<GraphicsGfxGroupPanel>([this]() {
110 if (gfx_group_panel_) {
111 status_ = gfx_group_panel_->Update();
112 }
113 }));
114
115 // Paletteset editor panel (separated from GfxGroupEditor for better UX)
116 panel_manager->RegisterEditorPanel(
117 std::make_unique<GraphicsPalettesetPanel>([this]() {
118 if (paletteset_panel_) {
119 status_ = paletteset_panel_->Update();
120 }
121 }));
122
123 // Prototype viewer for Super Donkey and dev format imports
124 panel_manager->RegisterEditorPanel(
125 std::make_unique<GraphicsPrototypeViewerPanel>([this]() {
127 }));
128}
129
130absl::Status GraphicsEditor::Load() {
131 gfx::ScopedTimer timer("GraphicsEditor::Load");
132
133 // Initialize all graphics sheets with appropriate palettes from ROM
134 // This ensures textures are created for editing
135 if (rom()->is_loaded()) {
136 auto& sheets = gfx::Arena::Get().gfx_sheets();
137
138 // Apply default palettes to all sheets based on common SNES ROM structure
139 // Sheets 0-112: Use overworld/dungeon palettes
140 // Sheets 113-127: Use sprite palettes
141 // Sheets 128-222: Use auxiliary/menu palettes
142
143 LOG_INFO("GraphicsEditor", "Initializing textures for %d graphics sheets",
145
146 int sheets_queued = 0;
147 for (int i = 0; i < zelda3::kNumGfxSheets; i++) {
148 if (!sheets[i].is_active() || !sheets[i].surface()) {
149 continue; // Skip inactive or surface-less sheets
150 }
151
152 // Palettes are now applied during ROM loading in LoadAllGraphicsData()
153 // Just queue texture creation for sheets that don't have textures yet
154 if (!sheets[i].texture()) {
155 // Fix: Ensure default palettes are applied if missing
156 // This handles the case where sheets are loaded but have no palette assigned
157 if (sheets[i].palette().empty()) {
158 // Default palette assignment logic
159 if (i <= 112) {
160 // Overworld/Dungeon sheets - use Dungeon Main palette (Group 0, Index 0)
161 if (game_data() && game_data()->palette_groups.dungeon_main.size() > 0) {
162 sheets[i].SetPaletteWithTransparent(
163 game_data()->palette_groups.dungeon_main.palette(0), 0);
164 }
165 } else if (i >= 113 && i <= 127) {
166 // Sprite sheets - use Sprites Aux1 palette (Group 4, Index 0)
167 if (game_data() && game_data()->palette_groups.sprites_aux1.size() > 0) {
168 sheets[i].SetPaletteWithTransparent(
169 game_data()->palette_groups.sprites_aux1.palette(0), 0);
170 }
171 } else {
172 // Menu/Aux sheets - use HUD palette if available, or fallback
173 if (game_data() && game_data()->palette_groups.hud.size() > 0) {
174 sheets[i].SetPaletteWithTransparent(
175 game_data()->palette_groups.hud.palette(0), 0);
176 }
177 }
178 }
179
182 sheets_queued++;
183 }
184 }
185
186 LOG_INFO("GraphicsEditor", "Queued texture creation for %d graphics sheets",
187 sheets_queued);
188 }
189
190 if (polyhedral_panel_) {
191 polyhedral_panel_->SetRom(rom_);
193 }
194
195 return absl::OkStatus();
196}
197
198absl::Status GraphicsEditor::Save() {
199 if (!rom_ || !rom_->is_loaded()) {
200 return absl::FailedPreconditionError("ROM not loaded");
201 }
202
203 // Only save sheets that have been modified
204 if (!state_.HasUnsavedChanges()) {
205 LOG_INFO("GraphicsEditor", "No modified sheets to save");
206 return absl::OkStatus();
207 }
208
209 LOG_INFO("GraphicsEditor", "Saving %zu modified graphics sheets",
210 state_.modified_sheets.size());
211
212 auto& sheets = gfx::Arena::Get().gfx_sheets();
213 std::set<uint16_t> saved_sheets;
214 std::vector<uint16_t> skipped_sheets;
215
216 for (uint16_t sheet_id : state_.modified_sheets) {
217 if (sheet_id >= zelda3::kNumGfxSheets) continue;
218
219 auto& sheet = sheets[sheet_id];
220 if (!sheet.is_active()) continue;
221
222 // Determine BPP and compression based on sheet range
223 int bpp = 3; // Default 3BPP
224 bool compressed = true;
225
226 // Sheets 113-114, 218+ are 2BPP
227 if (sheet_id == 113 || sheet_id == 114 || sheet_id >= 218) {
228 bpp = 2;
229 }
230
231 // Sheets 115-126 are uncompressed
232 if (sheet_id >= 115 && sheet_id <= 126) {
233 compressed = false;
234 }
235
236 if (bpp == 2) {
237 const size_t expected_size =
239 const size_t actual_size = sheet.vector().size();
240 if (actual_size < expected_size) {
241 LOG_WARN(
242 "GraphicsEditor",
243 "Skipping 2BPP sheet %02X save (expected %zu bytes, got %zu)",
244 sheet_id, expected_size, actual_size);
245 skipped_sheets.push_back(sheet_id);
246 continue;
247 }
248 }
249
250 // Calculate ROM offset for this sheet
251 // Get version constants from game_data
252 auto version_constants = zelda3::kVersionConstantsMap.at(game_data()->version);
253 uint32_t offset = zelda3::GetGraphicsAddress(
254 rom_->data(), static_cast<uint8_t>(sheet_id),
255 version_constants.kOverworldGfxPtr1,
256 version_constants.kOverworldGfxPtr2,
257 version_constants.kOverworldGfxPtr3, rom_->size());
258
259 // Convert 8BPP bitmap data to SNES planar format
260 auto snes_tile_data = gfx::IndexedToSnesSheet(sheet.vector(), bpp);
261
262 constexpr size_t kDecompressedSheetSize = 0x800;
263 std::vector<uint8_t> base_data;
264 if (compressed) {
265 auto decomp_result = gfx::lc_lz2::DecompressV2(
266 rom_->data(), offset, static_cast<int>(kDecompressedSheetSize), 1,
267 rom_->size());
268 if (!decomp_result.ok()) {
269 return decomp_result.status();
270 }
271 base_data = std::move(*decomp_result);
272 } else {
273 auto read_result =
274 rom_->ReadByteVector(offset, kDecompressedSheetSize);
275 if (!read_result.ok()) {
276 return read_result.status();
277 }
278 base_data = std::move(*read_result);
279 }
280
281 if (base_data.size() < snes_tile_data.size()) {
282 base_data.resize(snes_tile_data.size(), 0);
283 }
284 std::copy(snes_tile_data.begin(), snes_tile_data.end(),
285 base_data.begin());
286
287 std::vector<uint8_t> final_data;
288 if (compressed) {
289 // Compress using Hyrule Magic LC-LZ2
290 int compressed_size = 0;
291 auto compressed_data = gfx::HyruleMagicCompress(
292 base_data.data(), static_cast<int>(base_data.size()),
293 &compressed_size, 1);
294 final_data.assign(compressed_data.begin(),
295 compressed_data.begin() + compressed_size);
296 } else {
297 final_data = std::move(base_data);
298 }
299
300 // Write data to ROM buffer
301 for (size_t i = 0; i < final_data.size(); i++) {
302 rom_->WriteByte(offset + i, final_data[i]);
303 }
304
305 LOG_INFO("GraphicsEditor", "Saved sheet %02X (%zu bytes, %s) at offset %06X",
306 sheet_id, final_data.size(), compressed ? "compressed" : "raw",
307 offset);
308 saved_sheets.insert(sheet_id);
309 }
310
311 // Clear modified tracking after successful save
312 state_.ClearModifiedSheets(saved_sheets);
313 if (!skipped_sheets.empty()) {
314 return absl::FailedPreconditionError(
315 absl::StrCat("Skipped ", skipped_sheets.size(),
316 " 2BPP sheet(s); full data unavailable."));
317 }
318
319 return absl::OkStatus();
320}
321
323 // Panels are now drawn via PanelManager::DrawAllVisiblePanels()
324 // This Update() only handles editor-level state and keyboard shortcuts
325
326 // Handle editor-level keyboard shortcuts
328
330 return absl::OkStatus();
331}
332
334 // Skip if ImGui wants keyboard input
335 if (ImGui::GetIO().WantTextInput) {
336 return;
337 }
338
339 // Tool shortcuts (only when graphics editor is active)
340 if (ImGui::IsKeyPressed(ImGuiKey_V, false)) {
342 }
343 if (ImGui::IsKeyPressed(ImGuiKey_B, false)) {
345 }
346 if (ImGui::IsKeyPressed(ImGuiKey_E, false)) {
348 }
349 if (ImGui::IsKeyPressed(ImGuiKey_G, false) && !ImGui::GetIO().KeyCtrl) {
351 }
352 if (ImGui::IsKeyPressed(ImGuiKey_I, false)) {
354 }
355 if (ImGui::IsKeyPressed(ImGuiKey_L, false) && !ImGui::GetIO().KeyCtrl) {
357 }
358 if (ImGui::IsKeyPressed(ImGuiKey_R, false) && !ImGui::GetIO().KeyCtrl) {
360 }
361
362 // Zoom shortcuts
363 if (ImGui::IsKeyPressed(ImGuiKey_Equal, false) ||
364 ImGui::IsKeyPressed(ImGuiKey_KeypadAdd, false)) {
365 state_.ZoomIn();
366 }
367 if (ImGui::IsKeyPressed(ImGuiKey_Minus, false) ||
368 ImGui::IsKeyPressed(ImGuiKey_KeypadSubtract, false)) {
369 state_.ZoomOut();
370 }
371
372 // Grid toggle (Ctrl+G)
373 if (ImGui::GetIO().KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_G, false)) {
375 }
376
377 // Sheet navigation
378 if (ImGui::IsKeyPressed(ImGuiKey_PageDown, false)) {
379 NextSheet();
380 }
381 if (ImGui::IsKeyPressed(ImGuiKey_PageUp, false)) {
382 PrevSheet();
383 }
384}
385
388 ImGui::Begin("Memory Editor", &open_memory_editor_);
390 ImGui::End();
391 }
392
393 constexpr ImGuiTableFlags kGfxEditFlags = ImGuiTableFlags_Reorderable |
394 ImGuiTableFlags_Resizable |
395 ImGuiTableFlags_SizingStretchSame;
396
397 BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags)
398 SETUP_COLUMN("File Import (BIN, CGX, ROM)")
399 SETUP_COLUMN("Palette (COL)")
400 ImGui::TableSetupColumn("Tilemaps and Objects (SCR, PNL, OBJ)",
401 ImGuiTableColumnFlags_WidthFixed);
402 SETUP_COLUMN("Graphics Preview")
404 NEXT_COLUMN() {
409 }
410
411 NEXT_COLUMN() {
413 }
414
417 scr_loaded_, false, 0);
419
421 if (super_donkey_) {
422 // Super Donkey prototype graphics
423 for (size_t i = 0; i < num_sheets_to_load_ && i < gfx_sheets_.size(); i++) {
424 if (gfx_sheets_[i].is_active() && gfx_sheets_[i].texture()) {
425 ImGui::Image((ImTextureID)(intptr_t)gfx_sheets_[i].texture(),
426 ImVec2(128, 32));
427 if ((i + 1) % 4 != 0) {
428 ImGui::SameLine();
429 }
430 }
431 }
432 } else if (cgx_loaded_ && col_file_) {
433 // Load the CGX graphics
435 cgx_loaded_, true, 5);
436 } else {
437 // Load the BIN/Clipboard Graphics
439 gfx_loaded_, true, 2);
440 }
441 END_TABLE()
442}
443
444// =============================================================================
445// Prototype Viewer Import Methods
446// =============================================================================
447
449 gui::TextWithSeparators("Cgx Import");
450 InputInt("BPP", &current_bpp_);
451
452 InputText("##CGXFile", &cgx_file_name_);
453 SameLine();
454
455 if (ImGui::Button("Open CGX")) {
457 cgx_file_name_ = filename;
458 cgx_file_path_ = std::filesystem::absolute(filename).string();
459 is_open_ = true;
460 cgx_loaded_ = true;
461 }
462
463 if (ImGui::Button("Copy CGX Path")) {
464 ImGui::SetClipboardText(cgx_file_path_.c_str());
465 }
466
467 if (ImGui::Button("Load CGX Data")) {
470
471 cgx_bitmap_.Create(0x80, 0x200, 8, decoded_cgx_);
472 if (col_file_) {
476 }
477 }
478
479 return absl::OkStatus();
480}
481
483 InputText("##ScrFile", &scr_file_name_);
484
485 if (ImGui::Button("Open SCR")) {
487 scr_file_name_ = filename;
488 scr_file_path_ = std::filesystem::absolute(filename).string();
489 is_open_ = true;
490 scr_loaded_ = true;
491 }
492
493 InputInt("SCR Mod", &scr_mod_value_);
494
495 if (ImGui::Button("Load Scr Data")) {
497
498 decoded_scr_data_.resize(0x100 * 0x100);
501
502 scr_bitmap_.Create(0x100, 0x100, 8, decoded_scr_data_);
503 if (scr_loaded_) {
507 }
508 }
509
510 return absl::OkStatus();
511}
512
514 gui::TextWithSeparators("COL Import");
515 InputText("##ColFile", &col_file_name_);
516 SameLine();
517
518 if (ImGui::Button("Open COL")) {
520 col_file_name_ = filename;
521 col_file_path_ = std::filesystem::absolute(filename).string();
523 auto col_data_ = gfx::GetColFileData(temp_rom_.mutable_data());
524 if (col_file_palette_group_.size() != 0) {
526 }
527 auto col_file_palette_group_status =
529 if (col_file_palette_group_status.ok()) {
530 col_file_palette_group_ = col_file_palette_group_status.value();
531 }
533
534 // gigaleak dev format based code
536 col_file_ = true;
537 is_open_ = true;
538 }
539 HOVER_HINT(".COL, .BAK");
540
541 if (ImGui::Button("Copy Col Path")) {
542 ImGui::SetClipboardText(col_file_path_.c_str());
543 }
544
545 if (rom()->is_loaded()) {
546 gui::TextWithSeparators("ROM Palette");
547 gui::InputHex("Palette Index", &current_palette_index_);
548 ImGui::Combo("Palette", &current_palette_, kPaletteGroupAddressesKeys,
549 IM_ARRAYSIZE(kPaletteGroupAddressesKeys));
550 }
551
552 if (col_file_palette_.size() != 0) {
555 }
556
557 return absl::OkStatus();
558}
559
561 gui::TextWithSeparators("OBJ Import");
562
563 InputText("##ObjFile", &obj_file_path_);
564 SameLine();
565
566 if (ImGui::Button("Open OBJ")) {
568 obj_file_path_ = std::filesystem::absolute(filename).string();
570 is_open_ = true;
571 obj_loaded_ = true;
572 }
573 HOVER_HINT(".OBJ, .BAK");
574
575 return absl::OkStatus();
576}
577
579 gui::TextWithSeparators("Tilemap Import");
580
581 InputText("##TMapFile", &tilemap_file_path_);
582 SameLine();
583
584 if (ImGui::Button("Open Tilemap")) {
586 tilemap_file_path_ = std::filesystem::absolute(filename).string();
589
590 // Extract the high and low bytes from the file.
591 auto decomp_sheet = gfx::lc_lz2::DecompressV2(tilemap_rom_.data(), 0, 0x800,
594 tilemap_loaded_ = true;
595 is_open_ = true;
596 }
597 HOVER_HINT(".DAT, .BIN, .HEX");
598
599 return absl::OkStatus();
600}
601
603 gui::TextWithSeparators("BIN Import");
604
605 InputText("##ROMFile", &file_path_);
606 SameLine();
607
608 if (ImGui::Button("Open BIN")) {
610 file_path_ = filename;
612 is_open_ = true;
613 }
614 HOVER_HINT(".BIN, .HEX");
615
616 if (Button("Copy File Path")) {
617 ImGui::SetClipboardText(file_path_.c_str());
618 }
619
620 gui::InputHex("BIN Offset", &current_offset_);
621 gui::InputHex("BIN Size", &bin_size_);
622
623 if (Button("Decompress BIN")) {
624 if (file_path_.empty()) {
625 return absl::InvalidArgumentError(
626 "Please select a file before decompressing.");
627 }
629 }
630
631 return absl::OkStatus();
632}
633
635 gui::TextWithSeparators("Clipboard Import");
636 if (Button("Paste From Clipboard")) {
637 const char* text = ImGui::GetClipboardText();
638 if (text) {
639 const auto clipboard_data =
640 std::vector<uint8_t>(text, text + strlen(text));
641 ImGui::MemFree((void*)text);
642 status_ = temp_rom_.LoadFromData(clipboard_data);
643 is_open_ = true;
644 open_memory_editor_ = true;
645 }
646 }
649 gui::InputHex("Num Sheets", &num_sheets_to_load_);
650
651 if (Button("Decompress Clipboard Data")) {
652 if (temp_rom_.is_loaded()) {
653 status_ = DecompressImportData(0x40000);
654 } else {
655 status_ = absl::InvalidArgumentError(
656 "Please paste data into the clipboard before "
657 "decompressing.");
658 }
659 }
660
661 return absl::OkStatus();
662}
663
665 gui::TextWithSeparators("Experimental");
666 if (Button("Decompress Super Donkey Full")) {
667 if (file_path_.empty()) {
668 return absl::InvalidArgumentError(
669 "Please select `super_donkey_1.bin` before "
670 "importing.");
671 }
673 }
674 ImGui::SetItemTooltip(
675 "Requires `super_donkey_1.bin` to be imported under the "
676 "BIN import section.");
677 return absl::OkStatus();
678}
679
681 std::string title = "Memory Editor";
682 if (is_open_) {
683 static yaze::gui::MemoryEditorWidget mem_edit;
684 mem_edit.DrawWindow(title.c_str(), temp_rom_.mutable_data(),
685 temp_rom_.size());
686 }
687 return absl::OkStatus();
688}
689
692 temp_rom_.data(), current_offset_, size, 1,
693 temp_rom_.size()));
694
695 auto converted_sheet = gfx::SnesTo8bppSheet(import_data_, 3);
697 converted_sheet);
698
699 if (rom()->is_loaded() && game_data()) {
700 auto palette_group = game_data()->palette_groups.overworld_animated;
701 z3_rom_palette_ = palette_group[current_palette_];
702 if (col_file_) {
704 } else {
706 }
707 }
708
710 &bin_bitmap_);
711 gfx_loaded_ = true;
712
713 return absl::OkStatus();
714}
715
717 int i = 0;
718 for (const auto& offset : kSuperDonkeyTiles) {
719 int offset_value =
720 std::stoi(offset, nullptr, 16); // convert hex string to int
722 auto decompressed_data,
723 gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000, 1,
724 temp_rom_.size()));
725 auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
727 gfx::kTilesheetDepth, converted_sheet);
728 if (col_file_) {
729 gfx_sheets_[i].SetPalette(
731 } else {
732 // ROM palette
733 if (!game_data()) {
734 return absl::FailedPreconditionError("GameData not available");
735 }
736 auto palette_group = game_data()->palette_groups.get_group(
737 kPaletteGroupAddressesKeys[current_palette_]);
738 z3_rom_palette_ = palette_group->palette(current_palette_index_);
739 gfx_sheets_[i].SetPalette(z3_rom_palette_);
740 }
741
744 i++;
745 }
746
747 for (const auto& offset : kSuperDonkeySprites) {
748 int offset_value =
749 std::stoi(offset, nullptr, 16); // convert hex string to int
751 auto decompressed_data,
752 gfx::lc_lz2::DecompressV2(temp_rom_.data(), offset_value, 0x1000, 1,
753 temp_rom_.size()));
754 auto converted_sheet = gfx::SnesTo8bppSheet(decompressed_data, 3);
756 gfx::kTilesheetDepth, converted_sheet);
757 if (col_file_) {
758 gfx_sheets_[i].SetPalette(
760 } else {
761 // ROM palette
762 if (game_data()) {
763 auto palette_group = game_data()->palette_groups.get_group(
764 kPaletteGroupAddressesKeys[current_palette_]);
765 z3_rom_palette_ = palette_group->palette(current_palette_index_);
766 gfx_sheets_[i].SetPalette(z3_rom_palette_);
767 }
768 }
769
772 i++;
773 }
774 super_donkey_ = true;
776
777 return absl::OkStatus();
778}
779
785
791
792} // namespace editor
793} // namespace yaze
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length) const
Definition rom.cc:245
absl::Status LoadFromFile(const std::string &filename, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:75
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:290
auto mutable_data()
Definition rom.h:136
auto data() const
Definition rom.h:135
auto size() const
Definition rom.h:134
absl::Status LoadFromData(const std::vector< uint8_t > &data, const LoadOptions &options=LoadOptions::Defaults())
Definition rom.cc:148
bool is_loaded() const
Definition rom.h:128
zelda3::GameData * game_data() const
Definition editor.h:228
EditorDependencies dependencies_
Definition editor.h:237
bool HasUnsavedChanges() const
Check if any sheets have unsaved changes.
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
gfx::PaletteGroup col_file_palette_group_
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_
std::unique_ptr< PolyhedralEditorPanel > polyhedral_panel_
std::unique_ptr< PalettesetEditorPanel > paletteset_panel_
std::vector< uint8_t > import_data_
std::vector< SDL_Color > decoded_col_
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_
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:35
std::array< gfx::Bitmap, 223 > & gfx_sheets()
Get reference to all graphics sheets.
Definition arena.h:102
static Arena & Get()
Definition arena.cc:20
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
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< 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:1669
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:310
void TextWithSeparators(const absl::string_view &text)
Definition style.cc:1317
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:111
#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