feat(editor): enhance ScreenEditor with layer visibility controls and custom map loading/saving

- Added checkboxes for toggling visibility of title screen background layers (BG1 and BG2).
- Implemented a new method for rendering the composite view of the title screen.
- Introduced functionality for loading and saving custom maps from external binary files, enhancing user flexibility in map management.

Benefits:
- Improves user experience by allowing dynamic control over layer visibility during title screen editing.
- Expands the capabilities of the ScreenEditor with custom map handling, facilitating easier map modifications and sharing.
This commit is contained in:
scawful
2025-10-13 18:01:12 -04:00
parent 521df1f546
commit 26faa7e0af
4 changed files with 262 additions and 109 deletions

View File

@@ -748,23 +748,35 @@ void ScreenEditor::DrawTitleScreenEditor() {
ImGui::EndPopup();
}
// Layout: 3-column table for layers
if (ImGui::BeginTable("TitleScreenTable", 3,
// Layer visibility controls
bool prev_bg1 = show_title_bg1_;
bool prev_bg2 = show_title_bg2_;
ImGui::Checkbox("Show BG1", &show_title_bg1_);
ImGui::SameLine();
ImGui::Checkbox("Show BG2", &show_title_bg2_);
// Re-render composite if visibility changed
if (prev_bg1 != show_title_bg1_ || prev_bg2 != show_title_bg2_) {
status_ = title_screen_.RenderCompositeLayer(show_title_bg1_, show_title_bg2_);
if (status_.ok()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
&title_screen_.composite_bitmap());
}
}
// Layout: 2-column table (composite view + tile selector)
if (ImGui::BeginTable("TitleScreenTable", 2,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Borders)) {
ImGui::TableSetupColumn("BG1 Layer");
ImGui::TableSetupColumn("BG2 Layer");
ImGui::TableSetupColumn("Title Screen (Composite)");
ImGui::TableSetupColumn("Tile Selector");
ImGui::TableHeadersRow();
// Column 1: BG1 Canvas
// Column 1: Composite Canvas (BG1+BG2 stacked)
ImGui::TableNextColumn();
DrawTitleScreenBG1Canvas();
DrawTitleScreenCompositeCanvas();
// Column 2: BG2 Canvas
ImGui::TableNextColumn();
DrawTitleScreenBG2Canvas();
// Column 3: Blockset Selector
// Column 2: Blockset Selector
ImGui::TableNextColumn();
DrawTitleScreenBlocksetSelector();
@@ -772,6 +784,58 @@ void ScreenEditor::DrawTitleScreenEditor() {
}
}
void ScreenEditor::DrawTitleScreenCompositeCanvas() {
title_bg1_canvas_.DrawBackground();
title_bg1_canvas_.DrawContextMenu();
// Draw composite tilemap (BG1+BG2 stacked with transparency)
auto& composite_bitmap = title_screen_.composite_bitmap();
if (composite_bitmap.is_active()) {
title_bg1_canvas_.DrawBitmap(composite_bitmap, 0, 0, 2.0f, 255);
}
// Handle tile painting - always paint to BG1 layer
if (current_mode_ == EditingMode::DRAW && selected_title_tile16_ >= 0) {
if (title_bg1_canvas_.DrawTileSelector(8.0f)) {
if (!title_bg1_canvas_.points().empty()) {
auto click_pos = title_bg1_canvas_.points().front();
int tile_x = static_cast<int>(click_pos.x) / 8;
int tile_y = static_cast<int>(click_pos.y) / 8;
if (tile_x >= 0 && tile_x < 32 && tile_y >= 0 && tile_y < 32) {
int tilemap_index = tile_y * 32 + tile_x;
// Create tile word: tile_id | (palette << 10) | h_flip | v_flip
uint16_t tile_word = selected_title_tile16_ & 0x3FF;
tile_word |= (title_palette_ & 0x07) << 10;
if (title_h_flip_) tile_word |= 0x4000;
if (title_v_flip_) tile_word |= 0x8000;
// Update BG1 buffer and re-render both layers and composite
title_screen_.mutable_bg1_buffer()[tilemap_index] = tile_word;
status_ = title_screen_.RenderBG1Layer();
if (status_.ok()) {
// Update BG1 texture
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
&title_screen_.bg1_bitmap());
// Re-render and update composite
status_ = title_screen_.RenderCompositeLayer(show_title_bg1_, show_title_bg2_);
if (status_.ok()) {
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, &composite_bitmap);
}
}
}
}
}
}
title_bg1_canvas_.DrawGrid();
title_bg1_canvas_.DrawOverlay();
}
void ScreenEditor::DrawTitleScreenBG1Canvas() {
title_bg1_canvas_.DrawBackground();
title_bg1_canvas_.DrawContextMenu();
@@ -941,8 +1005,41 @@ void ScreenEditor::DrawOverworldMapEditor() {
gfx::Arena::TextureCommandType::UPDATE, &ow_map_screen_.map_bitmap());
}
}
ImGui::SameLine();
// Custom map load/save buttons
if (ImGui::Button("Load Custom Map...")) {
std::string path = util::FileDialogWrapper::ShowOpenFileDialog();
if (!path.empty()) {
status_ = ow_map_screen_.LoadCustomMap(path);
if (!status_.ok()) {
ImGui::OpenPopup("CustomMapLoadError");
}
}
}
ImGui::SameLine();
if (ImGui::Button("Save Custom Map...")) {
std::string path = util::FileDialogWrapper::ShowSaveFileDialog();
if (!path.empty()) {
status_ = ow_map_screen_.SaveCustomMap(path, ow_show_dark_world_);
if (status_.ok()) {
ImGui::OpenPopup("CustomMapSaveSuccess");
}
}
}
ImGui::SameLine();
ImGui::Text("Selected Tile: %d", selected_ow_tile_);
// Custom map error/success popups
if (ImGui::BeginPopup("CustomMapLoadError")) {
ImGui::Text("Error loading custom map: %s", status_.message().data());
ImGui::EndPopup();
}
if (ImGui::BeginPopup("CustomMapSaveSuccess")) {
ImGui::Text("Custom map saved successfully!");
ImGui::EndPopup();
}
// Save success popup
if (ImGui::BeginPopup("OWSaveSuccess")) {

View File

@@ -67,6 +67,7 @@ class ScreenEditor : public Editor {
void DrawInventoryToolset();
// Title screen layer editing
void DrawTitleScreenCompositeCanvas();
void DrawTitleScreenBG1Canvas();
void DrawTitleScreenBG2Canvas();
void DrawTitleScreenBlocksetSelector();
@@ -134,6 +135,8 @@ class ScreenEditor : public Editor {
bool title_h_flip_ = false;
bool title_v_flip_ = false;
int title_palette_ = 0;
bool show_title_bg1_ = true;
bool show_title_bg2_ = true;
// Overworld map screen state
int selected_ow_tile_ = 0;