Implement object selection rectangle functionality in DungeonEditor
- Added methods for object selection rectangle handling, including CheckForObjectSelection, DrawObjectSelectRect, and SelectObjectsInRect. - Enhanced DungeonEditor to support right-click drag selection for multiple objects, improving user interaction and object management. - Updated the UI in DungeonObjectSelector to optimize object previews and improve layout for better visibility. - Refactored various sections of DungeonEditor for code clarity and consistency, including adjustments to object rendering and selection processes.
This commit is contained in:
@@ -100,7 +100,8 @@ absl::Status DungeonEditor::Load() {
|
|||||||
room_selector_.set_rooms(&rooms_);
|
room_selector_.set_rooms(&rooms_);
|
||||||
room_selector_.set_entrances(&entrances_);
|
room_selector_.set_entrances(&entrances_);
|
||||||
room_selector_.set_active_rooms(active_rooms_);
|
room_selector_.set_active_rooms(active_rooms_);
|
||||||
room_selector_.set_room_selected_callback([this](int room_id) { OnRoomSelected(room_id); });
|
room_selector_.set_room_selected_callback(
|
||||||
|
[this](int room_id) { OnRoomSelected(room_id); });
|
||||||
|
|
||||||
canvas_viewer_.SetRom(rom_);
|
canvas_viewer_.SetRom(rom_);
|
||||||
canvas_viewer_.SetRooms(&rooms_);
|
canvas_viewer_.SetRooms(&rooms_);
|
||||||
@@ -115,11 +116,13 @@ absl::Status DungeonEditor::Load() {
|
|||||||
object_selector_.set_rooms(&rooms_);
|
object_selector_.set_rooms(&rooms_);
|
||||||
|
|
||||||
// Set up object selection callback
|
// Set up object selection callback
|
||||||
object_selector_.SetObjectSelectedCallback([this](const zelda3::RoomObject& object) {
|
object_selector_.SetObjectSelectedCallback(
|
||||||
preview_object_ = object;
|
[this](const zelda3::RoomObject& object) {
|
||||||
object_loaded_ = true;
|
preview_object_ = object;
|
||||||
placement_type_ = kObject; // Automatically switch to object placement mode
|
object_loaded_ = true;
|
||||||
});
|
placement_type_ =
|
||||||
|
kObject; // Automatically switch to object placement mode
|
||||||
|
});
|
||||||
|
|
||||||
is_loaded_ = true;
|
is_loaded_ = true;
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
@@ -131,20 +134,7 @@ absl::Status DungeonEditor::Update() {
|
|||||||
refresh_graphics_ = false;
|
refresh_graphics_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTabBar("##DungeonEditorTabBar")) {
|
status_ = UpdateDungeonRoomView();
|
||||||
if (ImGui::BeginTabItem("Room Editor")) {
|
|
||||||
status_ = UpdateDungeonRoomView();
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginTabItem("Usage Statistics")) {
|
|
||||||
if (is_loaded_) {
|
|
||||||
DrawUsageStats();
|
|
||||||
}
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
ImGui::EndTabBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
return absl::OkStatus();
|
return absl::OkStatus();
|
||||||
}
|
}
|
||||||
@@ -191,13 +181,13 @@ absl::Status DungeonEditor::RefreshGraphics() {
|
|||||||
|
|
||||||
void DungeonEditor::LoadDungeonRoomSize() {
|
void DungeonEditor::LoadDungeonRoomSize() {
|
||||||
std::map<int, std::vector<int>> rooms_by_bank;
|
std::map<int, std::vector<int>> rooms_by_bank;
|
||||||
for (const auto &room : room_size_addresses_) {
|
for (const auto& room : room_size_addresses_) {
|
||||||
int bank = room.second >> 16;
|
int bank = room.second >> 16;
|
||||||
rooms_by_bank[bank].push_back(room.second);
|
rooms_by_bank[bank].push_back(room.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process and calculate room sizes within each bank
|
// Process and calculate room sizes within each bank
|
||||||
for (auto &bank_rooms : rooms_by_bank) {
|
for (auto& bank_rooms : rooms_by_bank) {
|
||||||
// Sort the rooms within this bank
|
// Sort the rooms within this bank
|
||||||
std::ranges::sort(bank_rooms.second);
|
std::ranges::sort(bank_rooms.second);
|
||||||
|
|
||||||
@@ -207,7 +197,7 @@ void DungeonEditor::LoadDungeonRoomSize() {
|
|||||||
// Identify the room ID for the current room pointer
|
// Identify the room ID for the current room pointer
|
||||||
int room_id =
|
int room_id =
|
||||||
std::ranges::find_if(room_size_addresses_, [room_ptr](
|
std::ranges::find_if(room_size_addresses_, [room_ptr](
|
||||||
const auto &entry) {
|
const auto& entry) {
|
||||||
return entry.second == room_ptr;
|
return entry.second == room_ptr;
|
||||||
})->first;
|
})->first;
|
||||||
|
|
||||||
@@ -244,9 +234,11 @@ absl::Status DungeonEditor::UpdateDungeonRoomView() {
|
|||||||
|
|
||||||
// Correct 3-column layout as specified
|
// Correct 3-column layout as specified
|
||||||
if (BeginTable("#DungeonEditTable", 3, kDungeonTableFlags, ImVec2(0, 0))) {
|
if (BeginTable("#DungeonEditTable", 3, kDungeonTableFlags, ImVec2(0, 0))) {
|
||||||
TableSetupColumn("Room/Entrance Selector", ImGuiTableColumnFlags_WidthFixed, 250);
|
TableSetupColumn("Room/Entrance Selector", ImGuiTableColumnFlags_WidthFixed,
|
||||||
|
250);
|
||||||
TableSetupColumn("Canvas & Properties", ImGuiTableColumnFlags_WidthStretch);
|
TableSetupColumn("Canvas & Properties", ImGuiTableColumnFlags_WidthStretch);
|
||||||
TableSetupColumn("Object Selector/Editor", ImGuiTableColumnFlags_WidthFixed, 300);
|
TableSetupColumn("Object Selector/Editor", ImGuiTableColumnFlags_WidthFixed,
|
||||||
|
300);
|
||||||
TableHeadersRow();
|
TableHeadersRow();
|
||||||
TableNextRow();
|
TableNextRow();
|
||||||
|
|
||||||
@@ -296,12 +288,12 @@ void DungeonEditor::OnRoomSelected(int room_id) {
|
|||||||
void DungeonEditor::DrawToolset() {
|
void DungeonEditor::DrawToolset() {
|
||||||
if (BeginTable("DWToolset", 16, ImGuiTableFlags_SizingFixedFit,
|
if (BeginTable("DWToolset", 16, ImGuiTableFlags_SizingFixedFit,
|
||||||
ImVec2(0, 0))) {
|
ImVec2(0, 0))) {
|
||||||
static std::array<const char *, 16> tool_names = {
|
static std::array<const char*, 16> tool_names = {
|
||||||
"Undo", "Redo", "Separator", "Any", "BG1", "BG2",
|
"Undo", "Redo", "Separator", "Any", "BG1", "BG2",
|
||||||
"BG3", "Separator", "Object", "Sprite", "Item", "Entrance",
|
"BG3", "Separator", "Object", "Sprite", "Item", "Entrance",
|
||||||
"Door", "Chest", "Block", "Palette"};
|
"Door", "Chest", "Block", "Palette"};
|
||||||
std::ranges::for_each(tool_names,
|
std::ranges::for_each(tool_names,
|
||||||
[](const char *name) { TableSetupColumn(name); });
|
[](const char* name) { TableSetupColumn(name); });
|
||||||
|
|
||||||
TableNextColumn();
|
TableNextColumn();
|
||||||
if (Button(ICON_MD_UNDO)) {
|
if (Button(ICON_MD_UNDO)) {
|
||||||
@@ -416,7 +408,26 @@ void DungeonEditor::DrawToolset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Instructions: Click to place objects, Ctrl+Click to select, drag to move");
|
ImGui::Text(
|
||||||
|
"Instructions: Click to place objects, Ctrl+Click to select, drag to "
|
||||||
|
"move");
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
// Usage statistics as a popup to save space
|
||||||
|
if (ImGui::Button("Usage Statistics")) {
|
||||||
|
ImGui::OpenPopup("UsageStatsPopup");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupModal("UsageStatsPopup", nullptr,
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
if (is_loaded_) {
|
||||||
|
DrawUsageStats();
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Close")) {
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::DrawCanvasAndPropertiesPanel() {
|
void DungeonEditor::DrawCanvasAndPropertiesPanel() {
|
||||||
@@ -441,7 +452,8 @@ void DungeonEditor::DrawCanvasAndPropertiesPanel() {
|
|||||||
|
|
||||||
// Quick room info display
|
// Quick room info display
|
||||||
int current_room = current_room_id_;
|
int current_room = current_room_id_;
|
||||||
if (!active_rooms_.empty() && current_active_room_tab_ < active_rooms_.Size) {
|
if (!active_rooms_.empty() &&
|
||||||
|
current_active_room_tab_ < active_rooms_.Size) {
|
||||||
current_room = active_rooms_[current_active_room_tab_];
|
current_room = active_rooms_[current_active_room_tab_];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,6 +465,16 @@ void DungeonEditor::DrawCanvasAndPropertiesPanel() {
|
|||||||
ImGui::Text("Sprites: %zu", room.GetSprites().size());
|
ImGui::Text("Sprites: %zu", room.GetSprites().size());
|
||||||
ImGui::Text("Chests: %zu", room.GetChests().size());
|
ImGui::Text("Chests: %zu", room.GetChests().size());
|
||||||
|
|
||||||
|
// Selection info
|
||||||
|
if (!selected_object_indices_.empty()) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Selected Objects: %zu", selected_object_indices_.size());
|
||||||
|
if (ImGui::Button("Clear Selection")) {
|
||||||
|
selected_object_indices_.clear();
|
||||||
|
object_select_active_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
// Quick edit controls
|
// Quick edit controls
|
||||||
@@ -490,42 +512,59 @@ void DungeonEditor::DrawRoomPropertiesDebugPopup() {
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
// Room properties table
|
// Room properties table
|
||||||
if (ImGui::BeginTable("RoomPropertiesPopup", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
if (ImGui::BeginTable("RoomPropertiesPopup", 2,
|
||||||
|
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||||
ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 120);
|
ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 120);
|
||||||
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Room ID");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("%03X (%d)", current_room, current_room);
|
ImGui::Text("Room ID");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%03X (%d)", current_room, current_room);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Layout");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##layout", &room.layout);
|
ImGui::Text("Layout");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##layout", &room.layout);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Blockset");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##blockset", &room.blockset);
|
ImGui::Text("Blockset");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##blockset", &room.blockset);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Spriteset");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##spriteset", &room.spriteset);
|
ImGui::Text("Spriteset");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##spriteset", &room.spriteset);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Palette");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##palette", &room.palette);
|
ImGui::Text("Palette");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##palette", &room.palette);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Floor 1");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##floor1", &room.floor1);
|
ImGui::Text("Floor 1");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##floor1", &room.floor1);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Floor 2");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexByte("##floor2", &room.floor2);
|
ImGui::Text("Floor 2");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexByte("##floor2", &room.floor2);
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn(); ImGui::Text("Message ID");
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn(); gui::InputHexWord("##message_id", &room.message_id_);
|
ImGui::Text("Message ID");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
gui::InputHexWord("##message_id", &room.message_id_);
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
@@ -554,7 +593,6 @@ void DungeonEditor::DrawRoomPropertiesDebugPopup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DungeonEditor::DrawDungeonTabView() {
|
void DungeonEditor::DrawDungeonTabView() {
|
||||||
static int next_tab_id = 0;
|
static int next_tab_id = 0;
|
||||||
|
|
||||||
@@ -579,7 +617,7 @@ void DungeonEditor::DrawDungeonTabView() {
|
|||||||
|
|
||||||
if (BeginTabItem(zelda3::kRoomNames[active_rooms_[n]].data(), &open,
|
if (BeginTabItem(zelda3::kRoomNames[active_rooms_[n]].data(), &open,
|
||||||
ImGuiTabItemFlags_None)) {
|
ImGuiTabItemFlags_None)) {
|
||||||
current_active_room_tab_ = n; // Track which tab is currently active
|
current_active_room_tab_ = n; // Track which tab is currently active
|
||||||
DrawDungeonCanvas(active_rooms_[n]);
|
DrawDungeonCanvas(active_rooms_[n]);
|
||||||
EndTabItem();
|
EndTabItem();
|
||||||
}
|
}
|
||||||
@@ -649,7 +687,8 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
show_debug_popup = false;
|
show_debug_popup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal("Room Debug Info", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
if (ImGui::BeginPopupModal("Room Debug Info", nullptr,
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
static bool show_objects = false;
|
static bool show_objects = false;
|
||||||
ImGui::Checkbox("Show Object Outlines", &show_objects);
|
ImGui::Checkbox("Show Object Outlines", &show_objects);
|
||||||
|
|
||||||
@@ -675,21 +714,23 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
ImGui::Text("Objects: %zu", rooms_[room_id].GetTileObjects().size());
|
ImGui::Text("Objects: %zu", rooms_[room_id].GetTileObjects().size());
|
||||||
ImGui::Text("Layout Objects: %zu",
|
ImGui::Text("Layout Objects: %zu",
|
||||||
rooms_[room_id].GetLayout().GetObjects().size());
|
rooms_[room_id].GetLayout().GetObjects().size());
|
||||||
ImGui::Text("Sprites: %llu", static_cast<unsigned long long>(rooms_[room_id].GetSprites().size()));
|
ImGui::Text("Sprites: %llu", static_cast<unsigned long long>(
|
||||||
|
rooms_[room_id].GetSprites().size()));
|
||||||
ImGui::Text("Chests: %zu", rooms_[room_id].GetChests().size());
|
ImGui::Text("Chests: %zu", rooms_[room_id].GetChests().size());
|
||||||
|
|
||||||
// Palette information
|
// Palette information
|
||||||
ImGui::Text("Current Palette Group: %llu", static_cast<unsigned long long>(current_palette_group_id_));
|
ImGui::Text("Current Palette Group: %llu",
|
||||||
|
static_cast<unsigned long long>(current_palette_group_id_));
|
||||||
ImGui::Text("Palette Hash: %#016llx", last_palette_hash_);
|
ImGui::Text("Palette Hash: %#016llx", last_palette_hash_);
|
||||||
|
|
||||||
// Object type breakdown
|
// Object type breakdown
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Object Type Breakdown:");
|
ImGui::Text("Object Type Breakdown:");
|
||||||
std::map<int, int> object_type_counts;
|
std::map<int, int> object_type_counts;
|
||||||
for (const auto &obj : rooms_[room_id].GetTileObjects()) {
|
for (const auto& obj : rooms_[room_id].GetTileObjects()) {
|
||||||
object_type_counts[obj.id_]++;
|
object_type_counts[obj.id_]++;
|
||||||
}
|
}
|
||||||
for (const auto &[type, count] : object_type_counts) {
|
for (const auto& [type, count] : object_type_counts) {
|
||||||
ImGui::Text("Type 0x%02X: %d objects", type, count);
|
ImGui::Text("Type 0x%02X: %d objects", type, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,7 +760,7 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
|
|
||||||
if (selected_object_id >= 0 &&
|
if (selected_object_id >= 0 &&
|
||||||
selected_object_id < (int)rooms_[room_id].GetTileObjects().size()) {
|
selected_object_id < (int)rooms_[room_id].GetTileObjects().size()) {
|
||||||
const auto &selected_obj =
|
const auto& selected_obj =
|
||||||
rooms_[room_id].GetTileObjects()[selected_object_id];
|
rooms_[room_id].GetTileObjects()[selected_object_id];
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Selected Object:");
|
ImGui::Text("Selected Object:");
|
||||||
@@ -750,6 +791,9 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
canvas_.DrawBackground();
|
canvas_.DrawBackground();
|
||||||
canvas_.DrawContextMenu();
|
canvas_.DrawContextMenu();
|
||||||
|
|
||||||
|
// Handle object selection and placement
|
||||||
|
CheckForObjectSelection();
|
||||||
|
|
||||||
// Handle mouse input for drag and select functionality
|
// Handle mouse input for drag and select functionality
|
||||||
HandleCanvasMouseInput();
|
HandleCanvasMouseInput();
|
||||||
|
|
||||||
@@ -758,11 +802,11 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
const ImGuiIO& io = ImGui::GetIO();
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
ImVec2 mouse_pos = io.MousePos;
|
ImVec2 mouse_pos = io.MousePos;
|
||||||
ImVec2 canvas_pos = canvas_.zero_point();
|
ImVec2 canvas_pos = canvas_.zero_point();
|
||||||
ImVec2 canvas_mouse_pos = ImVec2(mouse_pos.x - canvas_pos.x, mouse_pos.y - canvas_pos.y);
|
ImVec2 canvas_mouse_pos =
|
||||||
auto [room_x, room_y] = CanvasToRoomCoordinates(
|
ImVec2(mouse_pos.x - canvas_pos.x, mouse_pos.y - canvas_pos.y);
|
||||||
static_cast<int>(canvas_mouse_pos.x),
|
auto [room_x, room_y] =
|
||||||
static_cast<int>(canvas_mouse_pos.y)
|
CanvasToRoomCoordinates(static_cast<int>(canvas_mouse_pos.x),
|
||||||
);
|
static_cast<int>(canvas_mouse_pos.y));
|
||||||
preview_object_.x_ = room_x;
|
preview_object_.x_ = room_x;
|
||||||
preview_object_.y_ = room_y;
|
preview_object_.y_ = room_y;
|
||||||
}
|
}
|
||||||
@@ -798,8 +842,8 @@ void DungeonEditor::DrawDungeonCanvas(int room_id) {
|
|||||||
canvas_.DrawOverlay();
|
canvas_.DrawOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::RenderObjectInCanvas(const zelda3::RoomObject &object,
|
void DungeonEditor::RenderObjectInCanvas(const zelda3::RoomObject& object,
|
||||||
const gfx::SnesPalette &palette) {
|
const gfx::SnesPalette& palette) {
|
||||||
// Validate ROM is loaded
|
// Validate ROM is loaded
|
||||||
if (!rom_ || !rom_->is_loaded()) {
|
if (!rom_ || !rom_->is_loaded()) {
|
||||||
return;
|
return;
|
||||||
@@ -831,7 +875,7 @@ void DungeonEditor::RenderObjectInCanvas(const zelda3::RoomObject &object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check cache first
|
// Check cache first
|
||||||
for (auto &cached : object_render_cache_) {
|
for (auto& cached : object_render_cache_) {
|
||||||
if (cached.object_id == object.id_ && cached.object_x == object.x_ &&
|
if (cached.object_id == object.id_ && cached.object_x == object.x_ &&
|
||||||
cached.object_y == object.y_ && cached.object_size == object.size_ &&
|
cached.object_y == object.y_ && cached.object_size == object.size_ &&
|
||||||
cached.palette_hash == palette_hash && cached.is_valid) {
|
cached.palette_hash == palette_hash && cached.is_valid) {
|
||||||
@@ -876,7 +920,7 @@ void DungeonEditor::RenderObjectInCanvas(const zelda3::RoomObject &object,
|
|||||||
object_render_cache_.push_back(std::move(cache_entry));
|
object_render_cache_.push_back(std::move(cache_entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::DisplayObjectInfo(const zelda3::RoomObject &object,
|
void DungeonEditor::DisplayObjectInfo(const zelda3::RoomObject& object,
|
||||||
int canvas_x, int canvas_y) {
|
int canvas_x, int canvas_y) {
|
||||||
// Display object information as text overlay
|
// Display object information as text overlay
|
||||||
std::string info_text = absl::StrFormat("ID:%d X:%d Y:%d S:%d", object.id_,
|
std::string info_text = absl::StrFormat("ID:%d X:%d Y:%d S:%d", object.id_,
|
||||||
@@ -886,12 +930,12 @@ void DungeonEditor::DisplayObjectInfo(const zelda3::RoomObject &object,
|
|||||||
canvas_.DrawText(info_text, canvas_x, canvas_y - 12);
|
canvas_.DrawText(info_text, canvas_x, canvas_y - 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::RenderLayoutObjects(const zelda3::RoomLayout &layout,
|
void DungeonEditor::RenderLayoutObjects(const zelda3::RoomLayout& layout,
|
||||||
const gfx::SnesPalette &palette) {
|
const gfx::SnesPalette& palette) {
|
||||||
// Render layout objects (walls, floors, etc.) as simple colored rectangles
|
// Render layout objects (walls, floors, etc.) as simple colored rectangles
|
||||||
// This provides a visual representation of the room's structure
|
// This provides a visual representation of the room's structure
|
||||||
|
|
||||||
for (const auto &layout_obj : layout.GetObjects()) {
|
for (const auto& layout_obj : layout.GetObjects()) {
|
||||||
// Convert room coordinates to canvas coordinates using helper function
|
// Convert room coordinates to canvas coordinates using helper function
|
||||||
auto [canvas_x, canvas_y] =
|
auto [canvas_x, canvas_y] =
|
||||||
RoomToCanvasCoordinates(layout_obj.x(), layout_obj.y());
|
RoomToCanvasCoordinates(layout_obj.x(), layout_obj.y());
|
||||||
@@ -942,15 +986,16 @@ void DungeonEditor::RenderLayoutObjects(const zelda3::RoomLayout &layout,
|
|||||||
std::pair<int, int> DungeonEditor::RoomToCanvasCoordinates(int room_x,
|
std::pair<int, int> DungeonEditor::RoomToCanvasCoordinates(int room_x,
|
||||||
int room_y) const {
|
int room_y) const {
|
||||||
// Convert room coordinates (16x16 tile units) to canvas coordinates (pixels)
|
// Convert room coordinates (16x16 tile units) to canvas coordinates (pixels)
|
||||||
// Note: The canvas applies global_scale_ and scrolling internally, so we return
|
// Note: The canvas applies global_scale_ and scrolling internally, so we
|
||||||
// the base coordinates and let the canvas handle the transformation
|
// return the base coordinates and let the canvas handle the transformation
|
||||||
return {room_x * 16, room_y * 16};
|
return {room_x * 16, room_y * 16};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int, int> DungeonEditor::CanvasToRoomCoordinates(int canvas_x,
|
std::pair<int, int> DungeonEditor::CanvasToRoomCoordinates(int canvas_x,
|
||||||
int canvas_y) const {
|
int canvas_y) const {
|
||||||
// Convert canvas coordinates (pixels) to room coordinates (16x16 tile units)
|
// Convert canvas coordinates (pixels) to room coordinates (16x16 tile units)
|
||||||
// Note: This assumes the canvas coordinates are already adjusted for scaling and scrolling
|
// Note: This assumes the canvas coordinates are already adjusted for scaling
|
||||||
|
// and scrolling
|
||||||
return {canvas_x / 16, canvas_y / 16};
|
return {canvas_x / 16, canvas_y / 16};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,10 +1035,13 @@ absl::Status DungeonEditor::LoadAndRenderRoomGraphics(int room_id) {
|
|||||||
auto palette_id = rom()->ReadWord(0xDEC4B + dungeon_palette_ptr);
|
auto palette_id = rom()->ReadWord(0xDEC4B + dungeon_palette_ptr);
|
||||||
if (palette_id.ok()) {
|
if (palette_id.ok()) {
|
||||||
current_palette_group_id_ = palette_id.value() / 180;
|
current_palette_group_id_ = palette_id.value() / 180;
|
||||||
if (current_palette_group_id_ < rom()->palette_group().dungeon_main.size()) {
|
if (current_palette_group_id_ <
|
||||||
full_palette_ = rom()->palette_group().dungeon_main[current_palette_group_id_];
|
rom()->palette_group().dungeon_main.size()) {
|
||||||
ASSIGN_OR_RETURN(current_palette_group_,
|
full_palette_ =
|
||||||
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
|
rom()->palette_group().dungeon_main[current_palette_group_id_];
|
||||||
|
ASSIGN_OR_RETURN(
|
||||||
|
current_palette_group_,
|
||||||
|
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1037,7 +1085,8 @@ void DungeonEditor::RenderRoomBackgroundLayers(int room_id) {
|
|||||||
|
|
||||||
// BG1 (background layer 1) - room graphics
|
// BG1 (background layer 1) - room graphics
|
||||||
auto& bg1_bitmap = gfx::Arena::Get().bg1().bitmap();
|
auto& bg1_bitmap = gfx::Arena::Get().bg1().bitmap();
|
||||||
if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) {
|
if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0 &&
|
||||||
|
bg1_bitmap.height() > 0) {
|
||||||
// Scale the background to fit the canvas
|
// Scale the background to fit the canvas
|
||||||
float scale_x = static_cast<float>(canvas_width) / bg1_bitmap.width();
|
float scale_x = static_cast<float>(canvas_width) / bg1_bitmap.width();
|
||||||
float scale_y = static_cast<float>(canvas_height) / bg1_bitmap.height();
|
float scale_y = static_cast<float>(canvas_height) / bg1_bitmap.height();
|
||||||
@@ -1053,7 +1102,8 @@ void DungeonEditor::RenderRoomBackgroundLayers(int room_id) {
|
|||||||
|
|
||||||
// BG2 (background layer 2) - sprite graphics (overlay)
|
// BG2 (background layer 2) - sprite graphics (overlay)
|
||||||
auto& bg2_bitmap = gfx::Arena::Get().bg2().bitmap();
|
auto& bg2_bitmap = gfx::Arena::Get().bg2().bitmap();
|
||||||
if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) {
|
if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0 &&
|
||||||
|
bg2_bitmap.height() > 0) {
|
||||||
// Scale the background to fit the canvas
|
// Scale the background to fit the canvas
|
||||||
float scale_x = static_cast<float>(canvas_width) / bg2_bitmap.width();
|
float scale_x = static_cast<float>(canvas_width) / bg2_bitmap.width();
|
||||||
float scale_y = static_cast<float>(canvas_height) / bg2_bitmap.height();
|
float scale_y = static_cast<float>(canvas_height) / bg2_bitmap.height();
|
||||||
@@ -1064,12 +1114,13 @@ void DungeonEditor::RenderRoomBackgroundLayers(int room_id) {
|
|||||||
int offset_x = (canvas_width - scaled_width) / 2;
|
int offset_x = (canvas_width - scaled_width) / 2;
|
||||||
int offset_y = (canvas_height - scaled_height) / 2;
|
int offset_y = (canvas_height - scaled_height) / 2;
|
||||||
|
|
||||||
canvas_.DrawBitmap(bg2_bitmap, offset_x, offset_y, scale, 200); // Semi-transparent overlay
|
canvas_.DrawBitmap(bg2_bitmap, offset_x, offset_y, scale,
|
||||||
|
200); // Semi-transparent overlay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::CalculateUsageStats() {
|
void DungeonEditor::CalculateUsageStats() {
|
||||||
for (const auto &room : rooms_) {
|
for (const auto& room : rooms_) {
|
||||||
if (blockset_usage_.find(room.blockset) == blockset_usage_.end()) {
|
if (blockset_usage_.find(room.blockset) == blockset_usage_.end()) {
|
||||||
blockset_usage_[room.blockset] = 1;
|
blockset_usage_[room.blockset] = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -1124,11 +1175,13 @@ void DungeonEditor::HandleCanvasMouseInput() {
|
|||||||
ImVec2 canvas_size = canvas_.canvas_size();
|
ImVec2 canvas_size = canvas_.canvas_size();
|
||||||
|
|
||||||
// Convert to canvas coordinates
|
// Convert to canvas coordinates
|
||||||
ImVec2 canvas_mouse_pos = ImVec2(mouse_pos.x - canvas_pos.x, mouse_pos.y - canvas_pos.y);
|
ImVec2 canvas_mouse_pos =
|
||||||
|
ImVec2(mouse_pos.x - canvas_pos.x, mouse_pos.y - canvas_pos.y);
|
||||||
|
|
||||||
// Handle mouse clicks
|
// Handle mouse clicks
|
||||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||||
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) {
|
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) ||
|
||||||
|
ImGui::IsKeyDown(ImGuiKey_RightCtrl)) {
|
||||||
// Start selection box
|
// Start selection box
|
||||||
is_selecting_ = true;
|
is_selecting_ = true;
|
||||||
select_start_pos_ = canvas_mouse_pos;
|
select_start_pos_ = canvas_mouse_pos;
|
||||||
@@ -1138,10 +1191,9 @@ void DungeonEditor::HandleCanvasMouseInput() {
|
|||||||
// Start dragging or place object
|
// Start dragging or place object
|
||||||
if (object_loaded_) {
|
if (object_loaded_) {
|
||||||
// Convert canvas coordinates to room coordinates
|
// Convert canvas coordinates to room coordinates
|
||||||
auto [room_x, room_y] = CanvasToRoomCoordinates(
|
auto [room_x, room_y] =
|
||||||
static_cast<int>(canvas_mouse_pos.x),
|
CanvasToRoomCoordinates(static_cast<int>(canvas_mouse_pos.x),
|
||||||
static_cast<int>(canvas_mouse_pos.y)
|
static_cast<int>(canvas_mouse_pos.y));
|
||||||
);
|
|
||||||
PlaceObjectAtPosition(room_x, room_y);
|
PlaceObjectAtPosition(room_x, room_y);
|
||||||
} else {
|
} else {
|
||||||
// Start dragging existing objects
|
// Start dragging existing objects
|
||||||
@@ -1184,13 +1236,11 @@ void DungeonEditor::DrawSelectBox() {
|
|||||||
|
|
||||||
// Calculate select box bounds
|
// Calculate select box bounds
|
||||||
ImVec2 start = ImVec2(
|
ImVec2 start = ImVec2(
|
||||||
canvas_pos.x + std::min(select_start_pos_.x, select_current_pos_.x),
|
canvas_pos.x + std::min(select_start_pos_.x, select_current_pos_.x),
|
||||||
canvas_pos.y + std::min(select_start_pos_.y, select_current_pos_.y)
|
canvas_pos.y + std::min(select_start_pos_.y, select_current_pos_.y));
|
||||||
);
|
|
||||||
ImVec2 end = ImVec2(
|
ImVec2 end = ImVec2(
|
||||||
canvas_pos.x + std::max(select_start_pos_.x, select_current_pos_.x),
|
canvas_pos.x + std::max(select_start_pos_.x, select_current_pos_.x),
|
||||||
canvas_pos.y + std::max(select_start_pos_.y, select_current_pos_.y)
|
canvas_pos.y + std::max(select_start_pos_.y, select_current_pos_.y));
|
||||||
);
|
|
||||||
|
|
||||||
// Draw selection box
|
// Draw selection box
|
||||||
draw_list->AddRect(start, end, IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
|
draw_list->AddRect(start, end, IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
|
||||||
@@ -1203,15 +1253,14 @@ void DungeonEditor::DrawDragPreview() {
|
|||||||
// Draw drag preview for selected objects
|
// Draw drag preview for selected objects
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
ImVec2 canvas_pos = canvas_.zero_point();
|
ImVec2 canvas_pos = canvas_.zero_point();
|
||||||
ImVec2 drag_delta = ImVec2(
|
ImVec2 drag_delta = ImVec2(drag_current_pos_.x - drag_start_pos_.x,
|
||||||
drag_current_pos_.x - drag_start_pos_.x,
|
drag_current_pos_.y - drag_start_pos_.y);
|
||||||
drag_current_pos_.y - drag_start_pos_.y
|
|
||||||
);
|
|
||||||
|
|
||||||
// Draw preview of where objects would be moved
|
// Draw preview of where objects would be moved
|
||||||
for (int obj_id : selected_objects_) {
|
for (int obj_id : selected_objects_) {
|
||||||
// TODO: Draw preview of object at new position
|
// TODO: Draw preview of object at new position
|
||||||
// This would require getting the object's current position and drawing it offset by drag_delta
|
// This would require getting the object's current position and drawing it
|
||||||
|
// offset by drag_delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1238,7 +1287,8 @@ void DungeonEditor::UpdateSelectedObjects() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DungeonEditor::IsObjectInSelectBox(const zelda3::RoomObject& object) const {
|
bool DungeonEditor::IsObjectInSelectBox(
|
||||||
|
const zelda3::RoomObject& object) const {
|
||||||
if (!is_selecting_) return false;
|
if (!is_selecting_) return false;
|
||||||
|
|
||||||
// Convert object position to canvas coordinates
|
// Convert object position to canvas coordinates
|
||||||
@@ -1251,8 +1301,8 @@ bool DungeonEditor::IsObjectInSelectBox(const zelda3::RoomObject& object) const
|
|||||||
float max_y = std::max(select_start_pos_.y, select_current_pos_.y);
|
float max_y = std::max(select_start_pos_.y, select_current_pos_.y);
|
||||||
|
|
||||||
// Check if object is within select box
|
// Check if object is within select box
|
||||||
return (canvas_x >= min_x && canvas_x <= max_x &&
|
return (canvas_x >= min_x && canvas_x <= max_x && canvas_y >= min_y &&
|
||||||
canvas_y >= min_y && canvas_y <= max_y);
|
canvas_y <= max_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DungeonEditor::PlaceObjectAtPosition(int room_x, int room_y) {
|
void DungeonEditor::PlaceObjectAtPosition(int room_x, int room_y) {
|
||||||
@@ -1284,4 +1334,110 @@ void DungeonEditor::PlaceObjectAtPosition(int room_x, int room_y) {
|
|||||||
object_selector_.set_current_room_id(current_room);
|
object_selector_.set_current_room_id(current_room);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DungeonEditor::CheckForObjectSelection() {
|
||||||
|
// Draw object selection rectangle similar to OverworldEditor
|
||||||
|
DrawObjectSelectRect();
|
||||||
|
|
||||||
|
// Handle object selection when rectangle is active
|
||||||
|
if (object_select_active_) {
|
||||||
|
SelectObjectsInRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DungeonEditor::DrawObjectSelectRect() {
|
||||||
|
if (!canvas_.IsMouseHovering()) return;
|
||||||
|
|
||||||
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
|
const ImVec2 canvas_pos = canvas_.zero_point();
|
||||||
|
const ImVec2 mouse_pos =
|
||||||
|
ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
|
||||||
|
|
||||||
|
static bool dragging = false;
|
||||||
|
static ImVec2 drag_start_pos;
|
||||||
|
|
||||||
|
// Right click to start object selection
|
||||||
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right) && !object_loaded_) {
|
||||||
|
drag_start_pos = mouse_pos;
|
||||||
|
object_select_start_ = mouse_pos;
|
||||||
|
selected_object_indices_.clear();
|
||||||
|
object_select_active_ = false;
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right drag to create selection rectangle
|
||||||
|
if (ImGui::IsMouseDragging(ImGuiMouseButton_Right) && !object_loaded_) {
|
||||||
|
object_select_end_ = mouse_pos;
|
||||||
|
dragging = true;
|
||||||
|
|
||||||
|
// Draw selection rectangle
|
||||||
|
ImVec2 start =
|
||||||
|
ImVec2(canvas_pos.x + std::min(drag_start_pos.x, mouse_pos.x),
|
||||||
|
canvas_pos.y + std::min(drag_start_pos.y, mouse_pos.y));
|
||||||
|
ImVec2 end = ImVec2(canvas_pos.x + std::max(drag_start_pos.x, mouse_pos.x),
|
||||||
|
canvas_pos.y + std::max(drag_start_pos.y, mouse_pos.y));
|
||||||
|
|
||||||
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
draw_list->AddRect(start, end, IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
|
||||||
|
draw_list->AddRectFilled(start, end, IM_COL32(255, 255, 0, 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete selection on mouse release
|
||||||
|
if (dragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
|
||||||
|
dragging = false;
|
||||||
|
object_select_active_ = true;
|
||||||
|
SelectObjectsInRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DungeonEditor::SelectObjectsInRect() {
|
||||||
|
int current_room = current_room_id_;
|
||||||
|
if (!active_rooms_.empty() && current_active_room_tab_ < active_rooms_.Size) {
|
||||||
|
current_room = active_rooms_[current_active_room_tab_];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_room < 0 || current_room >= rooms_.size()) return;
|
||||||
|
|
||||||
|
auto& room = rooms_[current_room];
|
||||||
|
selected_object_indices_.clear();
|
||||||
|
|
||||||
|
// Calculate selection bounds in room coordinates
|
||||||
|
auto [start_room_x, start_room_y] = CanvasToRoomCoordinates(
|
||||||
|
static_cast<int>(std::min(object_select_start_.x, object_select_end_.x)),
|
||||||
|
static_cast<int>(std::min(object_select_start_.y, object_select_end_.y)));
|
||||||
|
auto [end_room_x, end_room_y] = CanvasToRoomCoordinates(
|
||||||
|
static_cast<int>(std::max(object_select_start_.x, object_select_end_.x)),
|
||||||
|
static_cast<int>(std::max(object_select_start_.y, object_select_end_.y)));
|
||||||
|
|
||||||
|
// Find objects within selection rectangle
|
||||||
|
const auto& objects = room.GetTileObjects();
|
||||||
|
for (size_t i = 0; i < objects.size(); ++i) {
|
||||||
|
const auto& object = objects[i];
|
||||||
|
if (object.x_ >= start_room_x && object.x_ <= end_room_x &&
|
||||||
|
object.y_ >= start_room_y && object.y_ <= end_room_y) {
|
||||||
|
selected_object_indices_.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight selected objects
|
||||||
|
if (!selected_object_indices_.empty()) {
|
||||||
|
for (size_t index : selected_object_indices_) {
|
||||||
|
if (index < objects.size()) {
|
||||||
|
const auto& object = objects[index];
|
||||||
|
auto [canvas_x, canvas_y] =
|
||||||
|
RoomToCanvasCoordinates(object.x_, object.y_);
|
||||||
|
|
||||||
|
// Draw selection highlight
|
||||||
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
ImVec2 canvas_pos = canvas_.zero_point();
|
||||||
|
ImVec2 obj_start(canvas_pos.x + canvas_x - 2,
|
||||||
|
canvas_pos.y + canvas_y - 2);
|
||||||
|
ImVec2 obj_end(canvas_pos.x + canvas_x + 18,
|
||||||
|
canvas_pos.y + canvas_y + 18);
|
||||||
|
draw_list->AddRect(obj_start, obj_end, IM_COL32(0, 255, 255, 255), 0.0f,
|
||||||
|
0, 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace yaze::editor
|
} // namespace yaze::editor
|
||||||
|
|||||||
@@ -130,6 +130,11 @@ class DungeonEditor : public Editor {
|
|||||||
bool IsObjectInSelectBox(const zelda3::RoomObject& object) const;
|
bool IsObjectInSelectBox(const zelda3::RoomObject& object) const;
|
||||||
void PlaceObjectAtPosition(int room_x, int room_y);
|
void PlaceObjectAtPosition(int room_x, int room_y);
|
||||||
|
|
||||||
|
// Object selection rectangle (like OverworldEditor)
|
||||||
|
void CheckForObjectSelection();
|
||||||
|
void DrawObjectSelectRect();
|
||||||
|
void SelectObjectsInRect();
|
||||||
|
|
||||||
// Room graphics management
|
// Room graphics management
|
||||||
absl::Status LoadAndRenderRoomGraphics(int room_id);
|
absl::Status LoadAndRenderRoomGraphics(int room_id);
|
||||||
absl::Status ReloadAllRoomGraphics();
|
absl::Status ReloadAllRoomGraphics();
|
||||||
@@ -196,6 +201,12 @@ class DungeonEditor : public Editor {
|
|||||||
std::vector<int> selected_objects_;
|
std::vector<int> selected_objects_;
|
||||||
int current_layer_ = 0; // 0 = BG1, 1 = BG2, 2 = Both
|
int current_layer_ = 0; // 0 = BG1, 1 = BG2, 2 = Both
|
||||||
|
|
||||||
|
// Object selection rectangle (like OverworldEditor)
|
||||||
|
bool object_select_active_ = false;
|
||||||
|
ImVec2 object_select_start_;
|
||||||
|
ImVec2 object_select_end_;
|
||||||
|
std::vector<size_t> selected_object_indices_;
|
||||||
|
|
||||||
// New editor system integration
|
// New editor system integration
|
||||||
std::unique_ptr<zelda3::DungeonEditorSystem> dungeon_editor_system_;
|
std::unique_ptr<zelda3::DungeonEditorSystem> dungeon_editor_system_;
|
||||||
std::shared_ptr<zelda3::DungeonObjectEditor> object_editor_;
|
std::shared_ptr<zelda3::DungeonObjectEditor> object_editor_;
|
||||||
|
|||||||
@@ -119,9 +119,9 @@ void DungeonObjectSelector::DrawObjectBrowser() {
|
|||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
// Object list with previews
|
// Object list with previews - optimized for 300px column width
|
||||||
const int preview_size = 32; // 32x32 pixel preview
|
const int preview_size = 48; // Larger 48x48 pixel preview for better visibility
|
||||||
const int items_per_row = 4; // 4 items per row
|
const int items_per_row = 5; // 5 items per row to fit in 300px column
|
||||||
|
|
||||||
if (rom_ && rom_->is_loaded()) {
|
if (rom_ && rom_->is_loaded()) {
|
||||||
auto palette = rom_->palette_group().dungeon_main[current_palette_group_id_];
|
auto palette = rom_->palette_group().dungeon_main[current_palette_group_id_];
|
||||||
@@ -145,9 +145,11 @@ void DungeonObjectSelector::DrawObjectBrowser() {
|
|||||||
test_object.set_rom(rom_);
|
test_object.set_rom(rom_);
|
||||||
test_object.EnsureTilesLoaded();
|
test_object.EnsureTilesLoaded();
|
||||||
|
|
||||||
// Calculate position in grid
|
// Calculate position in grid - better sizing for 300px column
|
||||||
float item_width = (ImGui::GetContentRegionAvail().x - (items_per_row - 1) * ImGui::GetStyle().ItemSpacing.x) / items_per_row;
|
float available_width = ImGui::GetContentRegionAvail().x;
|
||||||
float item_height = preview_size + 40; // Preview + text
|
float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||||
|
float item_width = (available_width - (items_per_row - 1) * spacing) / items_per_row;
|
||||||
|
float item_height = preview_size + 30; // Preview + text (reduced padding)
|
||||||
|
|
||||||
ImGui::PushID(obj_id);
|
ImGui::PushID(obj_id);
|
||||||
|
|
||||||
@@ -196,9 +198,11 @@ void DungeonObjectSelector::DrawObjectBrowser() {
|
|||||||
"?");
|
"?");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw object ID and name
|
// Draw object ID and name with better positioning
|
||||||
ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 2, cursor_pos.y - 25));
|
ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 2, cursor_pos.y - 22));
|
||||||
ImGui::Text("0x%03X", obj_id);
|
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 255));
|
||||||
|
ImGui::Text("0x%02X", obj_id);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
// Try to get object name
|
// Try to get object name
|
||||||
std::string object_name = "Unknown";
|
std::string object_name = "Unknown";
|
||||||
@@ -227,8 +231,15 @@ void DungeonObjectSelector::DrawObjectBrowser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 2, cursor_pos.y - 10));
|
// Draw object name with better sizing
|
||||||
|
ImGui::SetCursorScreenPos(ImVec2(cursor_pos.x + 2, cursor_pos.y - 8));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(200, 200, 200, 255));
|
||||||
|
// Truncate long names to fit
|
||||||
|
if (object_name.length() > 8) {
|
||||||
|
object_name = object_name.substr(0, 8) + "...";
|
||||||
|
}
|
||||||
ImGui::Text("%s", object_name.c_str());
|
ImGui::Text("%s", object_name.c_str());
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
@@ -298,9 +309,9 @@ void DungeonObjectSelector::DrawRoomGraphics() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int current_block = 0;
|
int current_block = 0;
|
||||||
const int max_blocks_per_row = 4; // Limit blocks per row to fit canvas
|
const int max_blocks_per_row = 2; // 2 blocks per row for 300px column
|
||||||
const int block_width = 0x100; // 256 pixels per block
|
const int block_width = 128; // Reduced size to fit column
|
||||||
const int block_height = 0x40; // 64 pixels per block
|
const int block_height = 32; // Reduced height
|
||||||
|
|
||||||
for (int block : blocks) {
|
for (int block : blocks) {
|
||||||
if (current_block >= 16) break; // Only show first 16 blocks
|
if (current_block >= 16) break; // Only show first 16 blocks
|
||||||
|
|||||||
Reference in New Issue
Block a user