backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)

This commit is contained in:
scawful
2025-12-22 00:20:49 +00:00
parent 2934c82b75
commit 5c4cd57ff8
1259 changed files with 239160 additions and 43801 deletions

View File

@@ -5,7 +5,7 @@
#include <string>
#include "absl/strings/str_format.h"
#include "app/editor/system/editor_card_registry.h"
#include "app/editor/system/panel_manager.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gfx/resource/arena.h"
@@ -25,43 +25,70 @@ namespace editor {
constexpr uint32_t kRedPen = 0xFF0000FF;
void ScreenEditor::Initialize() {
if (!dependencies_.card_registry)
if (!dependencies_.panel_manager)
return;
auto* card_registry = dependencies_.card_registry;
auto* panel_manager = dependencies_.panel_manager;
card_registry->RegisterCard({.card_id = "screen.dungeon_maps",
.display_name = "Dungeon Maps",
.icon = ICON_MD_MAP,
.category = "Screen",
.shortcut_hint = "Alt+1",
.priority = 10});
card_registry->RegisterCard({.card_id = "screen.inventory_menu",
.display_name = "Inventory Menu",
.icon = ICON_MD_INVENTORY,
.category = "Screen",
.shortcut_hint = "Alt+2",
.priority = 20});
card_registry->RegisterCard({.card_id = "screen.overworld_map",
.display_name = "Overworld Map",
.icon = ICON_MD_PUBLIC,
.category = "Screen",
.shortcut_hint = "Alt+3",
.priority = 30});
card_registry->RegisterCard({.card_id = "screen.title_screen",
.display_name = "Title Screen",
.icon = ICON_MD_TITLE,
.category = "Screen",
.shortcut_hint = "Alt+4",
.priority = 40});
card_registry->RegisterCard({.card_id = "screen.naming_screen",
.display_name = "Naming Screen",
.icon = ICON_MD_EDIT,
.category = "Screen",
.shortcut_hint = "Alt+5",
.priority = 50});
panel_manager->RegisterPanel({.card_id = "screen.dungeon_maps",
.display_name = "Dungeon Maps",
.window_title = " Dungeon Map Editor",
.icon = ICON_MD_MAP,
.category = "Screen",
.shortcut_hint = "Alt+1",
.priority = 10,
.enabled_condition = [this]() { return rom()->is_loaded(); },
.disabled_tooltip = "Load a ROM first"});
panel_manager->RegisterPanel({.card_id = "screen.inventory_menu",
.display_name = "Inventory Menu",
.window_title = " Inventory Menu",
.icon = ICON_MD_INVENTORY,
.category = "Screen",
.shortcut_hint = "Alt+2",
.priority = 20,
.enabled_condition = [this]() { return rom()->is_loaded(); },
.disabled_tooltip = "Load a ROM first"});
panel_manager->RegisterPanel({.card_id = "screen.overworld_map",
.display_name = "Overworld Map",
.window_title = " Overworld Map",
.icon = ICON_MD_PUBLIC,
.category = "Screen",
.shortcut_hint = "Alt+3",
.priority = 30,
.enabled_condition = [this]() { return rom()->is_loaded(); },
.disabled_tooltip = "Load a ROM first"});
panel_manager->RegisterPanel({.card_id = "screen.title_screen",
.display_name = "Title Screen",
.window_title = " Title Screen",
.icon = ICON_MD_TITLE,
.category = "Screen",
.shortcut_hint = "Alt+4",
.priority = 40,
.enabled_condition = [this]() { return rom()->is_loaded(); },
.disabled_tooltip = "Load a ROM first"});
panel_manager->RegisterPanel({.card_id = "screen.naming_screen",
.display_name = "Naming Screen",
.window_title = " Naming Screen",
.icon = ICON_MD_EDIT,
.category = "Screen",
.shortcut_hint = "Alt+5",
.priority = 50,
.enabled_condition = [this]() { return rom()->is_loaded(); },
.disabled_tooltip = "Load a ROM first"});
// Register EditorPanel implementations
panel_manager->RegisterEditorPanel(std::make_unique<DungeonMapsPanel>(
[this]() { DrawDungeonMapsEditor(); }));
panel_manager->RegisterEditorPanel(std::make_unique<InventoryMenuPanel>(
[this]() { DrawInventoryMenuEditor(); }));
panel_manager->RegisterEditorPanel(std::make_unique<OverworldMapScreenPanel>(
[this]() { DrawOverworldMapEditor(); }));
panel_manager->RegisterEditorPanel(std::make_unique<TitleScreenPanel>(
[this]() { DrawTitleScreenEditor(); }));
panel_manager->RegisterEditorPanel(std::make_unique<NamingScreenPanel>(
[this]() { DrawNamingScreenEditor(); }));
// Show title screen by default
card_registry->ShowCard("screen.title_screen");
panel_manager->ShowPanel("screen.title_screen");
}
absl::Status ScreenEditor::Load() {
@@ -70,19 +97,20 @@ absl::Status ScreenEditor::Load() {
ASSIGN_OR_RETURN(dungeon_maps_,
zelda3::LoadDungeonMaps(*rom(), dungeon_map_labels_));
RETURN_IF_ERROR(zelda3::LoadDungeonMapTile16(
tile16_blockset_, *rom(), rom()->graphics_buffer(), false));
tile16_blockset_, *rom(), game_data(), game_data()->graphics_buffer,
false));
// Load graphics sheets and apply dungeon palette
sheets_.try_emplace(0, gfx::Arena::Get().gfx_sheets()[212]);
sheets_.try_emplace(1, gfx::Arena::Get().gfx_sheets()[213]);
sheets_.try_emplace(2, gfx::Arena::Get().gfx_sheets()[214]);
sheets_.try_emplace(3, gfx::Arena::Get().gfx_sheets()[215]);
sheets_[0] = std::make_unique<gfx::Bitmap>(gfx::Arena::Get().gfx_sheets()[212]);
sheets_[1] = std::make_unique<gfx::Bitmap>(gfx::Arena::Get().gfx_sheets()[213]);
sheets_[2] = std::make_unique<gfx::Bitmap>(gfx::Arena::Get().gfx_sheets()[214]);
sheets_[3] = std::make_unique<gfx::Bitmap>(gfx::Arena::Get().gfx_sheets()[215]);
// Apply dungeon palette to all sheets
for (int i = 0; i < 4; i++) {
sheets_[i].SetPalette(*rom()->mutable_dungeon_palette(3));
sheets_[i]->SetPalette(*game_data()->palette_groups.dungeon_main.mutable_palette(3));
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &sheets_[i]);
gfx::Arena::TextureCommandType::CREATE, sheets_[i].get());
}
// Create a single tilemap for tile8 graphics with on-demand texture creation
@@ -94,7 +122,7 @@ absl::Status ScreenEditor::Load() {
// Copy data from all 4 sheets into the combined bitmap
for (int sheet_idx = 0; sheet_idx < 4; sheet_idx++) {
const auto& sheet = sheets_[sheet_idx];
const auto& sheet = *sheets_[sheet_idx];
int dest_y_offset = sheet_idx * 32; // Each sheet is 32 pixels tall
for (int y = 0; y < 32; y++) {
@@ -113,7 +141,7 @@ absl::Status ScreenEditor::Load() {
tile8_tilemap_.tile_size = {8, 8};
tile8_tilemap_.map_size = {256, 256}; // Logical size for tile count
tile8_tilemap_.atlas.Create(tile8_width, tile8_height, 8, tile8_data);
tile8_tilemap_.atlas.SetPalette(*rom()->mutable_dungeon_palette(3));
tile8_tilemap_.atlas.SetPalette(*game_data()->palette_groups.dungeon_main.mutable_palette(3));
// Queue single texture creation for the atlas (not individual tiles)
gfx::Arena::Get().QueueTextureCommand(gfx::Arena::TextureCommandType::CREATE,
@@ -122,79 +150,9 @@ absl::Status ScreenEditor::Load() {
}
absl::Status ScreenEditor::Update() {
if (!dependencies_.card_registry)
return absl::OkStatus();
auto* card_registry = dependencies_.card_registry;
static gui::EditorCard dungeon_maps_card("Dungeon Maps", ICON_MD_MAP);
static gui::EditorCard inventory_menu_card("Inventory Menu",
ICON_MD_INVENTORY);
static gui::EditorCard overworld_map_card("Overworld Map", ICON_MD_PUBLIC);
static gui::EditorCard title_screen_card("Title Screen", ICON_MD_TITLE);
static gui::EditorCard naming_screen_card("Naming Screen",
ICON_MD_EDIT_ATTRIBUTES);
dungeon_maps_card.SetDefaultSize(800, 600);
inventory_menu_card.SetDefaultSize(800, 600);
overworld_map_card.SetDefaultSize(600, 500);
title_screen_card.SetDefaultSize(600, 500);
naming_screen_card.SetDefaultSize(500, 400);
// Dungeon Maps Card - Check visibility flag exists and is true before
// rendering
bool* dungeon_maps_visible =
card_registry->GetVisibilityFlag("screen.dungeon_maps");
if (dungeon_maps_visible && *dungeon_maps_visible) {
if (dungeon_maps_card.Begin(dungeon_maps_visible)) {
DrawDungeonMapsEditor();
}
dungeon_maps_card.End();
}
// Inventory Menu Card - Check visibility flag exists and is true before
// rendering
bool* inventory_menu_visible =
card_registry->GetVisibilityFlag("screen.inventory_menu");
if (inventory_menu_visible && *inventory_menu_visible) {
if (inventory_menu_card.Begin(inventory_menu_visible)) {
DrawInventoryMenuEditor();
}
inventory_menu_card.End();
}
// Overworld Map Card - Check visibility flag exists and is true before
// rendering
bool* overworld_map_visible =
card_registry->GetVisibilityFlag("screen.overworld_map");
if (overworld_map_visible && *overworld_map_visible) {
if (overworld_map_card.Begin(overworld_map_visible)) {
DrawOverworldMapEditor();
}
overworld_map_card.End();
}
// Title Screen Card - Check visibility flag exists and is true before
// rendering
bool* title_screen_visible =
card_registry->GetVisibilityFlag("screen.title_screen");
if (title_screen_visible && *title_screen_visible) {
if (title_screen_card.Begin(title_screen_visible)) {
DrawTitleScreenEditor();
}
title_screen_card.End();
}
// Naming Screen Card - Check visibility flag exists and is true before
// rendering
bool* naming_screen_visible =
card_registry->GetVisibilityFlag("screen.naming_screen");
if (naming_screen_visible && *naming_screen_visible) {
if (naming_screen_card.Begin(naming_screen_visible)) {
DrawNamingScreenEditor();
}
naming_screen_card.End();
}
// Panel drawing is handled centrally by PanelManager::DrawAllVisiblePanels()
// via the EditorPanel implementations registered in Initialize().
// No local drawing needed here - this fixes duplicate panel rendering.
return status_;
}
@@ -205,8 +163,8 @@ void ScreenEditor::DrawToolset() {
void ScreenEditor::DrawInventoryMenuEditor() {
static bool create = false;
if (!create && rom()->is_loaded()) {
status_ = inventory_.Create(rom());
if (!create && rom()->is_loaded() && game_data()) {
status_ = inventory_.Create(rom(), game_data());
if (status_.ok()) {
palette_ = inventory_.palette();
create = true;
@@ -227,18 +185,27 @@ void ScreenEditor::DrawInventoryMenuEditor() {
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
screen_canvas_.DrawBackground();
screen_canvas_.DrawContextMenu();
screen_canvas_.DrawBitmap(inventory_.bitmap(), 2, create);
screen_canvas_.DrawGrid(32.0f);
screen_canvas_.DrawOverlay();
{
gui::CanvasFrameOptions frame_opts;
frame_opts.draw_grid = true;
frame_opts.grid_step = 32.0f;
frame_opts.render_popups = true;
auto runtime = gui::BeginCanvas(screen_canvas_, frame_opts);
gui::DrawBitmap(runtime, inventory_.bitmap(), 2, create ? 1.0f : 0.0f);
gui::EndCanvas(screen_canvas_, runtime, frame_opts);
}
ImGui::TableNextColumn();
tilesheet_canvas_.DrawBackground(ImVec2(128 * 2 + 2, (192 * 2) + 4));
tilesheet_canvas_.DrawContextMenu();
tilesheet_canvas_.DrawBitmap(inventory_.tilesheet(), 2, create);
tilesheet_canvas_.DrawGrid(16.0f);
tilesheet_canvas_.DrawOverlay();
{
gui::CanvasFrameOptions frame_opts;
frame_opts.canvas_size = ImVec2(128 * 2 + 2, (192 * 2) + 4);
frame_opts.draw_grid = true;
frame_opts.grid_step = 16.0f;
frame_opts.render_popups = true;
auto runtime = gui::BeginCanvas(tilesheet_canvas_, frame_opts);
gui::DrawBitmap(runtime, inventory_.tilesheet(), 2, create ? 1.0f : 0.0f);
gui::EndCanvas(tilesheet_canvas_, runtime, frame_opts);
}
ImGui::TableNextColumn();
DrawInventoryItemIcons();
@@ -536,24 +503,42 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
gfx::ScopedTimer timer("screen_editor_draw_dungeon_maps_room_gfx");
if (ImGui::BeginChild("##DungeonMapTiles", ImVec2(0, 0), true)) {
// Enhanced tilesheet canvas with improved tile selection
tilesheet_canvas_.DrawBackground(ImVec2((256 * 2) + 2, (192 * 2) + 4));
tilesheet_canvas_.DrawContextMenu();
// Enhanced tilesheet canvas with BeginCanvas/EndCanvas pattern
{
gui::CanvasFrameOptions tilesheet_opts;
tilesheet_opts.canvas_size = ImVec2((256 * 2) + 2, (192 * 2) + 4);
tilesheet_opts.draw_grid = true;
tilesheet_opts.grid_step = 32.0f;
tilesheet_opts.render_popups = true;
// Interactive tile16 selector with grid snapping
if (tilesheet_canvas_.DrawTileSelector(32.f)) {
selected_tile16_ = tilesheet_canvas_.points().front().x / 32 +
(tilesheet_canvas_.points().front().y / 32) * 16;
auto tilesheet_rt = gui::BeginCanvas(tilesheet_canvas_, tilesheet_opts);
// Render selected tile16 and cache tile metadata
gfx::RenderTile16(nullptr, tile16_blockset_, selected_tile16_);
std::ranges::copy(tile16_blockset_.tile_info[selected_tile16_],
current_tile16_info.begin());
// Interactive tile16 selector with grid snapping
ImVec2 selected_pos;
if (gui::DrawTileSelector(tilesheet_rt, 32, 0, &selected_pos)) {
// Double-click detected - handle tile confirmation if needed
}
// Check for single-click selection (legacy compatibility)
if (tilesheet_canvas_.IsMouseHovering() &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
if (!tilesheet_canvas_.points().empty()) {
selected_tile16_ =
static_cast<int>(tilesheet_canvas_.points().front().x / 32 +
(tilesheet_canvas_.points().front().y / 32) * 16);
// Render selected tile16 and cache tile metadata
gfx::RenderTile16(nullptr, tile16_blockset_, selected_tile16_);
std::ranges::copy(tile16_blockset_.tile_info[selected_tile16_],
current_tile16_info.begin());
}
}
// Use stateless bitmap rendering for tilesheet
gui::DrawBitmap(tilesheet_rt, tile16_blockset_.atlas, 1, 1, 2.0F, 255);
gui::EndCanvas(tilesheet_canvas_, tilesheet_rt, tilesheet_opts);
}
// Use direct bitmap rendering for tilesheet
tilesheet_canvas_.DrawBitmap(tile16_blockset_.atlas, 1, 1, 2.0F, 255);
tilesheet_canvas_.DrawGrid(32.f);
tilesheet_canvas_.DrawOverlay();
if (!tilesheet_canvas_.points().empty() &&
!screen_canvas_.points().empty()) {
@@ -563,73 +548,84 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
}
ImGui::Separator();
current_tile_canvas_.DrawBackground(); // ImVec2(64 * 2 + 2, 64 * 2 + 4));
current_tile_canvas_.DrawContextMenu();
// Get tile8 from cache on-demand (only create texture when needed)
if (selected_tile8_ >= 0 && selected_tile8_ < 256) {
auto* cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
// Current tile canvas with BeginCanvas/EndCanvas pattern
{
gui::CanvasFrameOptions current_tile_opts;
current_tile_opts.draw_grid = true;
current_tile_opts.grid_step = 16.0f;
current_tile_opts.render_popups = true;
if (!cached_tile8) {
// Extract tile from atlas and cache it
const int tiles_per_row =
tile8_tilemap_.atlas.width() / 8; // 128 / 8 = 16
const int tile_x = (selected_tile8_ % tiles_per_row) * 8;
const int tile_y = (selected_tile8_ / tiles_per_row) * 8;
auto current_tile_rt =
gui::BeginCanvas(current_tile_canvas_, current_tile_opts);
// Extract 8x8 tile data from atlas
std::vector<uint8_t> tile_data(64);
for (int py = 0; py < 8; py++) {
for (int px = 0; px < 8; px++) {
int src_x = tile_x + px;
int src_y = tile_y + py;
int src_index = src_y * tile8_tilemap_.atlas.width() + src_x;
int dst_index = py * 8 + px;
// Get tile8 from cache on-demand (only create texture when needed)
if (selected_tile8_ >= 0 && selected_tile8_ < 256) {
auto* cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
if (src_index < tile8_tilemap_.atlas.size() && dst_index < 64) {
tile_data[dst_index] = tile8_tilemap_.atlas.data()[src_index];
if (!cached_tile8) {
// Extract tile from atlas and cache it
const int tiles_per_row =
tile8_tilemap_.atlas.width() / 8; // 128 / 8 = 16
const int tile_x = (selected_tile8_ % tiles_per_row) * 8;
const int tile_y = (selected_tile8_ / tiles_per_row) * 8;
// Extract 8x8 tile data from atlas
std::vector<uint8_t> tile_data(64);
for (int py = 0; py < 8; py++) {
for (int px = 0; px < 8; px++) {
int src_x = tile_x + px;
int src_y = tile_y + py;
int src_index = src_y * tile8_tilemap_.atlas.width() + src_x;
int dst_index = py * 8 + px;
if (src_index < tile8_tilemap_.atlas.size() && dst_index < 64) {
tile_data[dst_index] = tile8_tilemap_.atlas.data()[src_index];
}
}
}
gfx::Bitmap new_tile8(8, 8, 8, tile_data);
new_tile8.SetPalette(tile8_tilemap_.atlas.palette());
tile8_tilemap_.tile_cache.CacheTile(selected_tile8_,
std::move(new_tile8));
cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
}
gfx::Bitmap new_tile8(8, 8, 8, tile_data);
new_tile8.SetPalette(tile8_tilemap_.atlas.palette());
tile8_tilemap_.tile_cache.CacheTile(selected_tile8_,
std::move(new_tile8));
cached_tile8 = tile8_tilemap_.tile_cache.GetTile(selected_tile8_);
if (cached_tile8 && cached_tile8->is_active()) {
// Create texture on-demand only when needed
if (!cached_tile8->texture()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, cached_tile8);
}
// DrawTilePainter still uses member function (not yet migrated)
if (current_tile_canvas_.DrawTilePainter(*cached_tile8, 16)) {
// Modify the tile16 based on the selected tile and
// current_tile16_info
gfx::ModifyTile16(tile16_blockset_, game_data()->graphics_buffer,
current_tile16_info[0], current_tile16_info[1],
current_tile16_info[2], current_tile16_info[3],
212, selected_tile16_);
gfx::UpdateTile16(nullptr, tile16_blockset_, selected_tile16_);
}
}
}
if (cached_tile8 && cached_tile8->is_active()) {
// Create texture on-demand only when needed
if (!cached_tile8->texture()) {
// Get selected tile from cache and draw with stateless helper
auto* selected_tile =
tile16_blockset_.tile_cache.GetTile(selected_tile16_);
if (selected_tile && selected_tile->is_active()) {
// Ensure the selected tile has a valid texture
if (!selected_tile->texture()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, cached_tile8);
gfx::Arena::TextureCommandType::CREATE, selected_tile);
}
gui::DrawBitmap(current_tile_rt, *selected_tile, 2, 2, 4.0f, 255);
}
if (current_tile_canvas_.DrawTilePainter(*cached_tile8, 16)) {
// Modify the tile16 based on the selected tile and
// current_tile16_info
gfx::ModifyTile16(tile16_blockset_, rom()->graphics_buffer(),
current_tile16_info[0], current_tile16_info[1],
current_tile16_info[2], current_tile16_info[3], 212,
selected_tile16_);
gfx::UpdateTile16(nullptr, tile16_blockset_, selected_tile16_);
}
}
gui::EndCanvas(current_tile_canvas_, current_tile_rt, current_tile_opts);
}
// Get selected tile from cache
auto* selected_tile = tile16_blockset_.tile_cache.GetTile(selected_tile16_);
if (selected_tile && selected_tile->is_active()) {
// Ensure the selected tile has a valid texture
if (!selected_tile->texture()) {
// Queue texture creation via Arena's deferred system
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, selected_tile);
}
current_tile_canvas_.DrawBitmap(*selected_tile, 2, 2, 4.0f, 255);
}
current_tile_canvas_.DrawGrid(16.f);
current_tile_canvas_.DrawOverlay();
gui::InputTileInfo("TL", &current_tile16_info[0]);
ImGui::SameLine();
@@ -639,7 +635,7 @@ void ScreenEditor::DrawDungeonMapsRoomGfx() {
gui::InputTileInfo("BR", &current_tile16_info[3]);
if (ImGui::Button("Modify Tile16")) {
gfx::ModifyTile16(tile16_blockset_, rom()->graphics_buffer(),
gfx::ModifyTile16(tile16_blockset_, game_data()->graphics_buffer,
current_tile16_info[0], current_tile16_info[1],
current_tile16_info[2], current_tile16_info[3], 212,
selected_tile16_);
@@ -742,19 +738,19 @@ void ScreenEditor::LoadBinaryGfx() {
std::vector<uint8_t> bin_data((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
if (auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4);
zelda3::LoadDungeonMapTile16(tile16_blockset_, *rom(), converted_bin,
true)
zelda3::LoadDungeonMapTile16(tile16_blockset_, *rom(), game_data(),
converted_bin, true)
.ok()) {
sheets_.clear();
std::vector<std::vector<uint8_t>> gfx_sheets;
for (int i = 0; i < 4; i++) {
gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000),
converted_bin.begin() + ((i + 1) * 0x1000));
sheets_.emplace(i, gfx::Bitmap(128, 32, 8, gfx_sheets[i]));
sheets_[i].SetPalette(*rom()->mutable_dungeon_palette(3));
sheets_[i] = std::make_unique<gfx::Bitmap>(128, 32, 8, gfx_sheets[i]);
sheets_[i]->SetPalette(*game_data()->palette_groups.dungeon_main.mutable_palette(3));
// Queue texture creation via Arena's deferred system
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &sheets_[i]);
gfx::Arena::TextureCommandType::CREATE, sheets_[i].get());
}
binary_gfx_loaded_ = true;
} else {
@@ -767,8 +763,8 @@ void ScreenEditor::LoadBinaryGfx() {
void ScreenEditor::DrawTitleScreenEditor() {
// Initialize title screen on first draw
if (!title_screen_loaded_ && rom()->is_loaded()) {
status_ = title_screen_.Create(rom());
if (!title_screen_loaded_ && rom()->is_loaded() && game_data()) {
status_ = title_screen_.Create(rom(), game_data());
if (!status_.ok()) {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error loading title screen: %s",
status_.message().data());