10#include "absl/strings/str_format.h"
11#include "absl/strings/str_join.h"
22#include "imgui/imgui.h"
23#include "imgui/misc/cpp/imgui_stdlib.h"
51 if (ImGui::BeginTabBar(
"##SheetBrowserTabs")) {
52 const bool show_sheets = ImGui::BeginTabItem(tr(
"Sheets"));
59 const bool show_details = ImGui::BeginTabItem(tr(
"Details"));
62 ImGui::BeginChild(
"##SheetDetails", ImVec2(0, 0));
67 const bool show_png = ImGui::BeginTabItem(tr(
"PNG"));
70 ImGui::BeginChild(
"##SheetTransfer", ImVec2(0, 0));
77 return absl::OkStatus();
111std::string
HexList(
const std::vector<int>& values) {
112 if (values.empty()) {
115 return absl::StrJoin(values,
" ", [](std::string* out,
int value) {
116 out->append(absl::StrFormat(
"%02X", value));
121 ImGui::TableNextRow();
122 ImGui::TableSetColumnIndex(0);
123 ImGui::TextUnformatted(label);
124 ImGui::TableSetColumnIndex(1);
125 ImGui::Text(
"%zu", values.size());
126 ImGui::TableSetColumnIndex(2);
127 ImGui::TextWrapped(
"%s",
HexList(values).c_str());
145 ImGui::BeginDisabled(!can_edit);
146 ImGui::SetNextItemWidth(-1);
147 const bool submitted = ImGui::InputTextWithHint(
148 "##SheetLabel", tr(
"Sheet label (stored in the project)"), &
label_buffer_,
149 ImGuiInputTextFlags_EnterReturnsTrue);
150 if ((submitted || ImGui::IsItemDeactivatedAfterEdit()) && can_edit) {
152 label_status_ = status.ok() ?
"Label set; save the project to keep it"
153 : std::string(status.message());
159 std::ifstream file(path);
160 std::stringstream text;
161 text << file.rdbuf();
165 "Imported %d sheet label(s); existing labels "
168 : std::string(imported.status().message());
173 "Label sprite sheets from Oracle's \"Spritesets\" CSV: a cell like "
174 "\"0x46 Cannon Soldiers\" names sheet 0x46 + 0x73.");
175 ImGui::EndDisabled();
178 tr(
"Open the project that owns this ROM to edit "
188 if (!ImGui::CollapsingHeader(
189 absl::StrFormat(
"Sheet 0x%02X usage and free space###SheetUsage",
192 ImGuiTreeNodeFlags_DefaultOpen)) {
199 "Re-read the ROM buffer (saved sheets, group tables, areas, "
200 "rooms). Unsaved pixel edits are not included.");
203 HOVER_HINT(
"Outline empty, unreserved 16x16 blocks on the thumbnails");
214 const auto& entry =
inventory_->sheets[sheet_id];
219 if (entry.stored_bytes.has_value()) {
221 ImGui::Text(tr(
"stored %zu bytes"), *entry.stored_bytes);
223 if (entry.sprite_value.has_value()) {
225 ImGui::Text(tr(
"sprite value 0x%02X"), *entry.sprite_value);
227 if (!entry.error.empty()) {
230 if (entry.reserved) {
238 if (entry.engine_loaded) {
242 if (!entry.labels.empty()) {
243 ImGui::TextWrapped(
"%s", absl::StrJoin(entry.labels,
"; ").c_str());
246 const auto free_blocks = entry.FreeBlocks();
247 if (entry.has_block_stats) {
248 ImGui::Text(tr(
"Free 16x16 blocks: %zu of 16 (empty 8x8 tiles: %d)"),
249 free_blocks.size(), entry.empty_8x8);
250 if (!free_blocks.empty()) {
252 ImGui::TextDisabled(
"[%s]", HexList(free_blocks).c_str());
254 if (!entry.reserved_blocks.empty()) {
255 ImGui::Text(tr(
"Reserved blocks: %s"),
256 absl::StrJoin(entry.reserved_blocks,
" ").c_str());
260 if (ImGui::BeginTable(
"##SheetUsedBy", 3,
261 ImGuiTableFlags_SizingStretchProp |
262 ImGuiTableFlags_RowBg |
263 ImGuiTableFlags_BordersInnerH)) {
264 ImGui::TableSetupColumn(tr(
"Used by"), ImGuiTableColumnFlags_WidthFixed);
265 ImGui::TableSetupColumn(
"#", ImGuiTableColumnFlags_WidthFixed);
266 ImGui::TableSetupColumn(tr(
"Ids (hex)"));
267 ImGui::TableHeadersRow();
268 const auto& use = entry.usage;
269 if (entry.sprite_value.has_value()) {
270 DrawUsageRow(tr(
"Spritesets"), use.spritesets);
271 DrawUsageRow(tr(
"OW areas (sprites)"), use.ow_areas_sprite);
272 DrawUsageRow(tr(
"Rooms (sprites)"), use.rooms_sprite);
274 DrawUsageRow(tr(
"Main blocksets"), use.main_blocksets);
275 DrawUsageRow(tr(
"Room blocksets"), use.room_blocksets);
276 DrawUsageRow(tr(
"OW areas (static)"), use.ow_areas_static);
279 if (entry.unreferenced) {
280 ImGui::TextDisabled(tr(
"No table references this sheet."));
289 const auto& use =
inventory_->sheets[sheet_id].usage;
290 std::vector<std::string> parts;
291 auto add = [&parts](
size_t count,
const char* what) {
293 parts.push_back(absl::StrFormat(
"%zu %s", count, what));
296 add(use.main_blocksets.size(),
"main blocksets");
297 add(use.room_blocksets.size(),
"room blocksets");
298 add(use.spritesets.size(),
"spritesets");
299 add(use.ow_areas_static.size() + use.ow_areas_sprite.size(),
"OW areas");
300 add(use.rooms_sprite.size(),
"rooms");
301 return parts.empty() ? std::string(
"no table uses it")
302 :
"used by " + absl::StrJoin(parts,
", ");
309 if (!ImGui::CollapsingHeader(
310 absl::StrFormat(
"Pending graphics save (%zu)###PendingSave",
313 ImGuiTreeNodeFlags_DefaultOpen)) {
328 "Writes every dirty sheet to a scratch copy of the ROM and decodes it "
329 "back. Saving the ROM does the same for real, and writes nothing if any "
336 ImGui::TextDisabled(
"%s", tr(
"Check the plan before saving the ROM."));
341 tr(
"Edits changed since the check; check again."));
349 ImGui::TextColored(color,
"%s",
352 if (!usage.empty()) {
354 ImGui::TextDisabled(
"%s", usage.c_str());
370 return absl::FailedPreconditionError(
"Open a ROM to use room palettes");
375 target->sheet_id != sheet_id || target->palette.size() != 8) {
376 return absl::FailedPreconditionError(
377 "Use Edit Graphics from a source tile to supply its palette");
380 for (
int i = 0; i < 8; ++i) {
381 const auto rgb = target->palette[i].rgb();
382 palette[i] = {
static_cast<uint8_t
>(rgb.x),
static_cast<uint8_t
>(rgb.y),
383 static_cast<uint8_t
>(rgb.z)};
391 return context.status();
393 return absl::FailedPreconditionError(
394 "Choose a room slot that loads the selected sheet");
396 return context->colors;
406 if (!ImGui::CollapsingHeader(tr(
"PNG export and import###SheetPng"))) {
410 const bool arena_is_ours =
game_data_ !=
nullptr &&
412 if (!arena_is_ours) {
414 tr(
"The sheets in memory belong to another open ROM."));
418 const char* modes[] = {tr(
"Grayscale"), tr(
"Background row (left half)"),
419 tr(
"Room sprite row"), tr(
"Room background slot"),
420 tr(
"Selected source tile")};
421 ImGui::SetNextItemWidth(180.0f);
423 IM_ARRAYSIZE(modes));
425 ImGui::SetNextItemWidth(90.0f);
426 ImGui::InputInt(tr(
"Room##png"), &
png_room_, 1, 16,
427 ImGuiInputTextFlags_CharsHexadecimal);
431 ImGui::SetNextItemWidth(90.0f);
435 "The room picks the palette rows and, for room PNGs, the room's 8 "
436 "background sheets.");
437 ImGui::EndDisabled();
441 "%s", target !=
nullptr
442 ? target->label.c_str()
443 :
"Use Edit Graphics from the tile you want to work on.");
449 std::vector<int> matches;
450 for (
int slot = 0; slot < 8; ++slot) {
451 if (set.sheets[slot] == sheet_id)
452 matches.push_back(slot);
458 auto slot_label = [&](
int slot) {
459 return absl::StrFormat(
460 "Slot %d / %s half", slot,
465 const std::string selected =
466 png_room_slot_ < 0 ? (matches.empty() ?
"Sheet not loaded by this room"
467 :
"Choose a loaded slot")
469 if (ImGui::BeginCombo(tr(
"Loaded slot##png"), selected.c_str())) {
470 for (
int slot : matches) {
471 if (ImGui::Selectable(slot_label(slot).c_str(),
479 "Uses the saved room header and its default entrance graphics. "
480 "Inherited entrance "
481 "choices may differ from a particular gameplay route. PNG "
482 "indices stay 0-7; slot 7's animation overlay is not included.");
484 ImGui::SetNextItemWidth(320.0f);
485 ImGui::InputTextWithHint(
"File##PngPath", tr(
"empty: choose in a dialog"),
488 "PNG path for the export and import buttons. Leave it empty to choose "
489 "the file in a dialog.");
490 ImGui::SetNextItemWidth(90.0f);
494 "The 16x16 block (0-15, 8 per row) where an imported sheet PNG starts; "
495 "pick a free block from the usage list above.");
498 const std::vector<uint8_t> pixels = sheet_id < sheets.size()
499 ? sheets[sheet_id].vector()
500 : std::vector<uint8_t>{};
502 png_filter.
filters.push_back({
"PNG image",
"png"});
504 auto save_path = [
this](
const std::string& default_name) {
509 auto open_path = [
this, &png_filter]() {
517 auto png = palette.ok()
519 : absl::StatusOr<std::vector<uint8_t>>(palette.status());
521 SetPngStatus(std::string(png.status().message()),
true);
523 const std::string path =
524 save_path(absl::StrFormat(
"sheet_%02X", sheet_id));
528 status.ok() ?
"Exported " + path : std::string(status.message()),
536 const std::string path = palette.ok() ? open_path() : std::string();
538 SetPngStatus(std::string(palette.status().message()),
true);
539 }
else if (!path.empty()) {
544 : absl::StatusOr<SheetPngImportPreview>(bytes.status());
547 SetPngStatus(std::string(preview.status().message()),
true);
559 SetPngStatus(std::string(palette.status().message()),
true);
566 SetPngStatus(std::string(png.status().message()),
true);
568 const std::string path =
569 save_path(absl::StrFormat(
"room_%03X_background",
png_room_));
573 status.ok() ?
"Exported " + path +
" (sheets as saved in the ROM)"
574 : std::string(status.message()),
581 "128x256: the room's 8 background sheets in slot order, read from the "
582 "ROM (save pixel edits first to include them). This legacy layout uses "
583 "one uniform palette for all slots.");
587 const std::string path = palette.ok() ? open_path() : std::string();
589 SetPngStatus(std::string(palette.status().message()),
true);
590 }
else if (!path.empty() &&
rom_ !=
nullptr &&
game_data_ !=
nullptr) {
597 : absl::StatusOr<std::vector<SheetPngImportPreview>>(
600 if (!previews.ok()) {
601 SetPngStatus(std::string(previews.status().message()),
true);
605 std::vector<std::string> unsaved;
606 for (
const auto& preview : *previews) {
608 unsaved.push_back(absl::StrFormat(
"0x%02X", preview.sheet_id));
611 if (!unsaved.empty()) {
612 SetPngStatus(absl::StrFormat(
"Save or discard the pixel edits to "
613 "sheet(s) %s before a room import",
614 absl::StrJoin(unsaved,
", ")),
624 ImGui::EndDisabled();
627 "Room slot colors apply to one sheet. Use Export sheet "
628 "PNG for the selected slot.");
638 bool any_change =
false;
641 any_change = any_change || !preview.changed_tiles.empty();
643 ImGui::BeginDisabled(!any_change);
645 std::vector<std::string> errors;
647 const absl::Status status =
650 errors.push_back(std::string(status.message()));
653 SetPngStatus(errors.empty() ? std::string(
"Imported; save the ROM to write "
655 : absl::StrJoin(errors,
"; "),
659 ImGui::EndDisabled();
668 ImGui::Text(tr(
"Search:"));
672 ImGuiInputTextFlags_CharsHexadecimal)) {
675 int value =
static_cast<int>(strtol(
search_buffer_,
nullptr, 16));
676 if (value >= 0 && value <= 222) {
685 ImGui::OpenPopup(
"Sheet filters");
688 HOVER_HINT(
"Filter range, modified sheets, and thumbnail size");
689 if (ImGui::BeginPopup(
"Sheet filters")) {
690 ImGui::SetNextItemWidth(70);
691 ImGui::DragInt(
"First", &
filter_min_, 1.0f, 0, 222,
"%02X");
692 ImGui::SetNextItemWidth(70);
693 ImGui::DragInt(
"Last", &
filter_max_, 1.0f, 0, 222,
"%02X");
726 ImGui::BeginChild(
"##SheetGridChild", ImVec2(0, 0),
true,
727 ImGuiWindowFlags_AlwaysVerticalScrollbar);
732 const float fit_scale =
734 std::max(0.25f, (ImGui::GetContentRegionAvail().x - 12) / 128));
735 const float thumb_width = 128 * fit_scale;
736 const float thumb_height = 32 * fit_scale;
737 const float padding = 4.0f;
740 float available_width = ImGui::GetContentRegionAvail().x;
742 1,
static_cast<int>(available_width / (thumb_width + padding * 2)));
772 const float fit_scale =
774 std::max(0.25f, (ImGui::GetContentRegionAvail().x - 12) / 128));
775 const float thumb_width = 128 * fit_scale;
776 const float thumb_height = 32 * fit_scale;
780 bool is_multi_selected =
786 std::optional<gui::StyleColorGuard> sel_bg_guard;
790 sel_bg_guard.emplace(ImGuiCol_ChildBg, sel_bg);
791 }
else if (is_multi_selected) {
794 sel_bg_guard.emplace(ImGuiCol_ChildBg, multi_bg);
797 ImGui::BeginChild(absl::StrFormat(
"##Sheet%02X", sheet_id).c_str(),
798 ImVec2(thumb_width + 8, thumb_height + 24),
true,
799 ImGuiWindowFlags_NoScrollbar);
802 preview_opts.
canvas_size = ImVec2(thumb_width + 1, thumb_height + 1);
803 preview_opts.
dest_pos = ImVec2(2, 2);
804 preview_opts.
dest_size = ImVec2(thumb_width - 2, thumb_height - 2);
805 preview_opts.
grid_step = 8.0f * fit_scale;
823 std::string label = absl::StrFormat(
"%02X", sheet_id);
829 ImVec2 text_pos = ImGui::GetCursorScreenPos();
830 ImVec2 text_size = ImGui::CalcTextSize(label.c_str());
832 ImVec2(2, 2), ImVec2(text_size.x + 4, text_size.y + 2),
833 is_modified ? ImGui::GetColorU32(IM_COL32(180, 100, 0, 200))
834 : ImGui::GetColorU32(IM_COL32(0, 100, 0, 180)));
838 is_modified ? ImGui::GetColorU32(IM_COL32(255, 200, 100, 255))
839 : ImGui::GetColorU32(IM_COL32(150, 255, 150, 255)));
845 ImGui::GetWindowDrawList()->AddCircleFilled(
850 sheet_id <
static_cast<int>(
inventory_->sheets.size())) {
851 const auto& entry =
inventory_->sheets[sheet_id];
852 const float block_w = preview_opts.
dest_size.x / 8.0f;
853 const float block_h = preview_opts.
dest_size.y / 2.0f;
855 for (
int block : entry.FreeBlocks()) {
857 ImVec2(preview_opts.
dest_pos.x + (block % 8) * block_w,
858 preview_opts.
dest_pos.y + (block / 8) * block_h),
859 ImVec2(block_w, block_h),
860 entry.flagged ? ImGui::GetColorU32(IM_COL32(230, 180, 40, 70))
861 : ImGui::GetColorU32(IM_COL32(60, 200, 90, 70)));
865 entry.reserved ?
"RES" : (entry.flagged ?
"ASK" :
nullptr);
866 if (badge !=
nullptr) {
867 const ImVec2 badge_size = ImGui::CalcTextSize(badge);
868 const ImVec2 badge_pos(thumb_width - badge_size.x - 4, 2);
870 badge_pos, ImVec2(badge_size.x + 4, badge_size.y + 2),
871 entry.reserved ? ImGui::GetColorU32(IM_COL32(170, 30, 30, 220))
872 : ImGui::GetColorU32(IM_COL32(170, 120, 20, 220)));
874 ImVec2(badge_pos.x + 2, badge_pos.y), badge,
875 ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)));
882 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
883 if (ImGui::GetIO().KeyCtrl) {
885 if (is_multi_selected) {
897 if (ImGui::IsItemHovered() &&
898 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
904 sel_bg_guard.reset();
907 if (ImGui::IsItemHovered()) {
908 ImGui::BeginTooltip();
909 ImGui::Text(tr(
"Sheet: 0x%02X (%d)"), sheet_id, sheet_id);
910 if (
const std::string label =
SheetLabel(
static_cast<uint16_t
>(sheet_id));
912 ImGui::TextUnformatted(label.c_str());
915 ImGui::Text(tr(
"Size: %dx%d"), bitmap.
width(), bitmap.
height());
916 ImGui::Text(tr(
"Depth: %d bpp"), bitmap.
depth());
918 ImGui::Text(tr(
"(Inactive)"));
924 sheet_id <
static_cast<int>(
inventory_->sheets.size())) {
925 const auto& entry =
inventory_->sheets[sheet_id];
926 if (entry.reserved) {
928 }
else if (entry.flagged) {
931 if (entry.has_block_stats) {
932 ImGui::Text(tr(
"Free 16x16 blocks: %zu"), entry.FreeBlocks().size());
934 if (!entry.labels.empty()) {
935 ImGui::TextUnformatted(absl::StrJoin(entry.labels,
"; ").c_str());
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
std::set< uint16_t > selected_sheets
std::set< uint16_t > modified_sheets
uint16_t current_sheet_id
std::set< uint16_t > open_sheets
zelda3::GameData * game_data
void SelectSheet(uint16_t sheet_id)
Select a sheet for editing.
const GraphicsEditTarget * SourceTarget() const
void DrawBatchOperations()
Draw batch operation buttons.
absl::StatusOr< zelda3::SheetPalette > PngPalette(int sheet_id=-1)
std::function< const project::YazeProject *()> project_getter_
UndoManager * undo_manager_
bool png_status_is_error_
const Rom * inventory_rom_
std::string label_buffer_
void Draw(bool *p_open) override
Draw the sheet browser UI.
const std::optional< zelda3::GfxSheetInventory > & inventory() const
void DrawPngTransfer(uint16_t sheet_id)
std::string inventory_error_
std::string save_plan_error_
std::optional< zelda3::GfxSheetInventory > inventory_
std::string label_status_
LabelImporter label_importer_
std::string SheetUsageSummary(uint16_t sheet_id) const
SavePlanner save_planner_
void SetDataSources(Rom *rom, zelda3::GameData *game_data, std::function< const project::YazeProject *()> project_getter)
Where free-block and "used by" data come from. The project getter may return null (no project open).
GraphicsEditorState * state_
void RefreshInventory()
Rebuild the sheet inventory from the ROM buffer. Runs lazily on the first draw and when the ROM chang...
void DrawSheetLabelEditor(uint16_t sheet_id)
zelda3::GameData * game_data_
void DrawSelectedSheetInfo()
Storage, reserved state, free 16x16 blocks and "used by" for the current sheet.
void SetPngStatus(std::string message, bool is_error)
void DrawSearchBar()
Draw the search/filter bar.
void Initialize()
Initialize the panel.
LabelSetter label_setter_
void DrawSheetThumbnail(int sheet_id, gfx::Bitmap &bitmap)
Draw a single sheet thumbnail.
gui::Canvas thumbnail_canvas_
std::vector< GraphicsSavePlanEntry > save_plan_
std::vector< SheetPngImportPreview > png_pending_
std::set< uint16_t > save_plan_sheets_
std::string SheetLabel(uint16_t sheet) const
void DrawSheetGrid()
Draw the sheet grid view.
absl::Status Update()
Legacy Update method for backward compatibility.
const void * gfx_sheets_owner() const
GraphicsSheets & gfx_sheets()
Represents a bitmap image optimized for SNES ROM hacking.
void AddTextAt(ImVec2 local_pos, const std::string &text, uint32_t color)
void AddRectFilledAt(ImVec2 local_top_left, ImVec2 size, uint32_t color)
CanvasConfig & GetConfig()
static float GetHexInputWidth()
static float GetSliderWidth()
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
3bpp graphics sheets to and from indexed PNGs.
#define ICON_MD_FILE_DOWNLOAD
#define ICON_MD_FILE_UPLOAD
#define ICON_MD_FACT_CHECK
#define ICON_MD_UPLOAD_FILE
#define ICON_MD_SELECT_ALL
#define HOVER_HINT(string)
zelda3::GfxSheetInventoryOptions BuildGfxSheetInventoryOptions(const project::YazeProject *project)
std::string GetGraphicsSheetLabel(const project::YazeProject &project, uint16_t sheet)
void DrawUsageRow(const char *label, const std::vector< int > &values)
std::string HexList(const std::vector< int > &values)
absl::StatusOr< std::vector< uint8_t > > ExportSheetPixelsPng(uint16_t sheet_id, const std::vector< uint8_t > &indexed_pixels, const zelda3::SheetPalette &palette)
std::string DescribeSheetPngImport(const SheetPngImportPreview &preview)
"Sheet 0x20: blocks 0, 3 (5 tiles)" for the preview list.
std::string DescribeGraphicsSavePlanEntry(const GraphicsSavePlanEntry &entry)
"Sheet 0x92: in place at 0x0AED16, 1476 -> 1473 bytes".
absl::StatusOr< std::vector< SheetPngImportPreview > > PreviewRoomPngImport(const Rom &rom, const zelda3::RoomBackgroundSet &set, const std::vector< uint8_t > &png_bytes, const zelda3::SheetPalette &palette)
absl::StatusOr< SheetPngImportPreview > PreviewSheetPngImport(uint16_t sheet_id, const std::vector< uint8_t > &indexed_pixels, const std::vector< uint8_t > &png_bytes, const zelda3::SheetPalette &palette, int first_block)
absl::Status ApplySheetPngImport(const SheetPngImportPreview &preview, GraphicsEditorState &state, UndoManager *undo_manager)
void EndCanvas(Canvas &canvas)
void DrawBitmapPreview(const CanvasRuntime &rt, gfx::Bitmap &bitmap, const BitmapPreviewOptions &options)
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
ImVec4 GetSelectedColor()
ImVec4 GetModifiedColor()
absl::Status WriteBinaryFile(const std::string &path, const std::vector< uint8_t > &bytes)
absl::StatusOr< std::vector< uint8_t > > ReadBinaryFile(const std::string &path)
std::vector< RoomBackgroundSet > ResolveAllRoomBackgroundSets(const Rom &rom, const GameData &data)
All 296 rooms' background sets (header bytes read from the ROM).
absl::StatusOr< RoomSheetPaletteContext > ResolveRoomSheetPalette(Rom &rom, GameData &data, int room, int slot, int row)
absl::StatusOr< std::vector< uint8_t > > ExportRoomBackgroundPng(const Rom &rom, const RoomBackgroundSet &set, const SheetPalette &palette)
Room LoadRoomHeaderFromRom(Rom *rom, int room_id)
std::map< int, OverworldAreaGfxInfo > CollectOverworldAreaGfx(Rom &rom, GameData *game_data)
const char * GfxSheetInventoryKindName(GfxSheetStorageKind kind)
RoomBackgroundSet ResolveRoomBackgroundSet(const GameData &data, int room, uint8_t header_blockset)
absl::StatusOr< GfxSheetInventory > BuildGfxSheetInventory(const Rom &rom, const std::map< int, OverworldAreaGfxInfo > &areas, const std::map< int, RoomGfxInfo > &rooms, const GfxSheetInventoryOptions &options)
std::map< int, RoomGfxInfo > CollectRoomGfx(const Rom &rom)
constexpr uint32_t kNumGfxSheets
int DungeonBackgroundPaletteOffset(uint8_t main_blockset, int destination_slot)
std::array< SheetColor, 8 > SheetPalette
Colors for 3bpp indices 0-7. Index 0 is exported as transparent.
absl::StatusOr< SheetPalette > RoomSpriteSheetPalette(Rom &rom, GameData &data, int room, int row)
Sprite palette row (OAM palette 0-7, CGRAM row 8 + row) of room room.
SheetPalette GrayscaleSheetPalette()
absl::StatusOr< SheetPalette > RoomBackgroundSheetPalette(Rom &rom, GameData &data, int room, int row)
std::optional< float > grid_step
std::optional< float > grid_step
Modern project structure with comprehensive settings consolidation.
std::vector< FileDialogFilter > filters