21 return lhs.
id_ == rhs.
id_ && lhs.
x() == rhs.
x() && lhs.
y() == rhs.
y() &&
33 return absl::FailedPreconditionError(
"Room export is unavailable");
38absl::StatusOr<DungeonRoomTransferPlan>
40 int source_room_id,
const std::string& json,
46 return absl::FailedPreconditionError(
47 "Room replacement is not editable in this view");
60 return absl::FailedPreconditionError(
61 "Room replacement is not editable in this view");
66absl::StatusOr<DungeonConnectionPlan>
74 return absl::FailedPreconditionError(
75 "Open this room in the canvas to preview its connection");
87 return absl::FailedPreconditionError(
88 "Door connections are not editable in this view");
97 return absl::FailedPreconditionError(
"Room properties are not editable");
103 const std::vector<RoomMetadataRequest>& requests) {
105 return absl::FailedPreconditionError(
"Room properties are not editable");
107 for (
const auto& request : requests) {
109 return absl::FailedPreconditionError(
"Room properties are not loaded");
116 uint8_t item_id,
bool big_chest) {
119 return absl::FailedPreconditionError(
"Chest contents are not editable");
127 return absl::FailedPreconditionError(
"Chests are not editable");
167 if (room && (!state.room_settings ||
168 state.room_settings->first != room->layer_merging() ||
169 state.room_settings->second != room->effect())) {
170 state.manager.ApplyLayerMerging(room->layer_merging());
171 state.manager.ApplyRoomEffect(room->effect());
172 state.room_settings = std::make_pair(room->layer_merging(), room->effect());
178 state.manager.ApplyGameLayerRegisters(room->GameLayerRegisters());
180 return state.manager;
189 int pixel_w,
int pixel_h) {
191 const int x = std::clamp(pixel_x, 0, kDungeonCanvasPixelSize - 1);
192 const int y = std::clamp(pixel_y, 0, kDungeonCanvasPixelSize - 1);
194 std::clamp(pixel_w, 1, std::max(1, kDungeonCanvasPixelSize - x));
196 std::clamp(pixel_h, 1, std::max(1, kDungeonCanvasPixelSize - y));
202 const std::vector<zelda3::RoomObject>& previous_objects,
203 const std::vector<zelda3::RoomObject>& next_objects) {
207 const auto [x, y, w, h] =
213 const size_t count = std::max(previous_objects.size(), next_objects.size());
214 for (
size_t i = 0; i < count; ++i) {
215 const bool has_previous = i < previous_objects.size();
216 const bool has_next = i < next_objects.size();
217 if (has_previous && has_next &&
218 HasSameObjectIdentity(previous_objects[i], next_objects[i])) {
222 append_object_rect(previous_objects[i]);
225 append_object_rect(next_objects[i]);
238 auto apply_list = [](std::array<bool, 256>& dest,
239 const std::vector<uint16_t>& values) {
241 for (uint16_t value : values) {
247 auto ids_valid = [](
const std::vector<uint16_t>& values) {
248 std::array<bool, 256> seen{};
249 for (uint16_t value : values) {
250 if (value >= seen.size() || seen[value]) {
258 std::vector<uint16_t> default_track_tile_list;
259 for (uint16_t tile = 0xB0; tile <= 0xBE; ++tile) {
260 default_track_tile_list.push_back(tile);
262 const std::vector<uint16_t> default_stop_tile_list = {0xB7, 0xB8, 0xB9, 0xBA};
263 const std::vector<uint16_t> default_switch_tile_list = {0xD0, 0xD1, 0xD2,
266 const auto& track_tiles =
269 : default_track_tile_list;
273 const auto& stop_tiles =
276 : default_stop_tile_list;
279 const auto& switch_tiles =
282 : default_switch_tile_list;
292 std::vector<uint16_t> minecart_ids = {0xA3};
296 for (uint16_t
id : minecart_ids) {
352 if (ImGui::GetCurrentContext() ==
nullptr) {
355 const int frame = ImGui::GetFrameCount();
365 return item.second.last_used_frame >= 0 &&
366 item.second.last_used_frame < frame - 1;
385 if (ImGui::Checkbox(
"Tracks##canvas_tracks", &tracks)) {
400 if (active_room !=
nullptr) {
426 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
427 const bool viewport_visible = ImGui::BeginChild(
428 "##DungeonRoomViewport", ImVec2(0, 0),
false,
429 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
430 ImGui::PopStyleVar();
431 if (!viewport_visible) {
438 const bool pointer_pressed = ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
439 ImGui::IsMouseClicked(ImGuiMouseButton_Right) ||
440 ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
442 ImGui::GetFrameCount());
455 if (active_room !=
nullptr) {
470 bool pointer_pressed,
473 if (pointer_pressed) {
479 int frame_index)
const {
488 !ImGui::GetCurrentContext()) {
493 if (elapsed >= kChangePingDurationSeconds) {
503 if (index >= objects.size()) {
506 const auto [x, y, w, h] =
509 rects.push_back(
ChangePingRect{x, y, std::max(w, 8), std::max(h, 8)});
512 auto selected_entities =
518 switch (entity.type) {
519 case EntityType::Door: {
520 const auto& doors = room.
GetDoors();
521 if (entity.index < doors.size()) {
522 const auto [x, y, w, h] = doors[entity.index].GetEditorBounds();
528 case EntityType::Sprite: {
530 if (entity.index < sprites.size()) {
532 sprites[entity.index].y() * 16, 16,
537 case EntityType::Item: {
539 if (entity.index < pot_items.size()) {
540 rects.push_back(
ChangePingRect{pot_items[entity.index].GetPixelX(),
541 pot_items[entity.index].GetPixelY(),
546 case EntityType::Object:
547 case EntityType::None:
555 ChangePingRect{0, 0, kDungeonCanvasPixelSize, kDungeonCanvasPixelSize});
558 const float progress =
559 static_cast<float>(elapsed / kChangePingDurationSeconds);
560 const float remaining = std::clamp(1.0f - progress, 0.0f, 1.0f);
561 const float expand = 4.0f + 12.0f * progress;
563 ImVec4 fill = theme.dungeon_selection_pulsing;
564 fill.w = 0.18f * remaining;
565 ImVec4 border = theme.dungeon_selection_primary;
566 border.w = 0.95f * remaining;
567 const ImU32 fill_color = ImGui::GetColorU32(fill);
568 const ImU32 border_color = ImGui::GetColorU32(border);
570 const ImVec2 viewport_min = canvas_rt.
canvas_p0;
576 static_cast<float>(rect.x) * canvas_rt.
scale - expand,
578 static_cast<float>(rect.y) * canvas_rt.
scale - expand);
580 min.x +
static_cast<float>(rect.w) * canvas_rt.
scale + expand * 2.0f,
581 min.y +
static_cast<float>(rect.h) * canvas_rt.
scale + expand * 2.0f);
583 const bool visible = max.x >= viewport_min.x && min.x <= viewport_max.x &&
584 max.y >= viewport_min.y && min.y <= viewport_max.y;
586 canvas_rt.
draw_list->AddRectFilled(min, max, fill_color, 2.0f);
587 canvas_rt.
draw_list->AddRect(min, max, border_color, 2.0f, 0,
588 2.0f + 2.0f * remaining);
594 (
static_cast<float>(rect.x) +
static_cast<float>(rect.w) * 0.5f) *
597 (
static_cast<float>(rect.y) +
static_cast<float>(rect.h) * 0.5f) *
599 const float marker_min_x = viewport_min.x + 8.0f;
600 const float marker_min_y = viewport_min.y + 8.0f;
601 const float marker_max_x = std::max(marker_min_x, viewport_max.x - 8.0f);
602 const float marker_max_y = std::max(marker_min_y, viewport_max.y - 8.0f);
603 const ImVec2 clamped(std::clamp(center.x, marker_min_x, marker_max_x),
604 std::clamp(center.y, marker_min_y, marker_max_y));
605 canvas_rt.
draw_list->AddCircleFilled(clamped, 5.0f + 4.0f * remaining,
607 canvas_rt.
draw_list->AddCircle(clamped, 7.0f + 6.0f * remaining,
608 border_color, 18, 2.0f);
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
InteractionContext * context() const
Get the interaction context.
void Sync(const Rom *rom, const project::YazeProject *project, const zelda3::Room &room)
void DrawControls(bool interactive)
void RecordVisitedRoom(int room_id)
RoomTransferPreviewCallback room_transfer_preview_callback_
void PruneConnectedRoomCompositeOutputs()
void PopulateCanvasContextMenu(int room_id)
void DrawChangePingOverlay(const gui::CanvasRuntime &canvas_rt, const zelda3::Room &room)
void ApplyTrackCollisionConfig()
DungeonRoomTransferEditorState room_transfer_state_
std::vector< int > recently_visited_rooms_
std::bitset< 256 > minecart_sprite_ids_
std::vector< uint16_t > track_tile_order_
DungeonRoomStore * rooms() const
ChestDeleteCallback chest_delete_callback_
void SyncCanvasCaptureRegion(const gui::CanvasRuntime &canvas_rt)
absl::Status ApplyRoomTransfer(const DungeonRoomTransferPlan &plan)
absl::StatusOr< std::string > ExportRoomDocument(int room_id)
RoomTransferApplyCallback room_transfer_apply_callback_
int connected_composite_prune_frame_
DoorConnectionPreviewCallback door_connection_preview_callback_
ChestEditCallback chest_edit_callback_
void UpdateRoomCanvasShortcutFocus(bool hovered, bool pointer_pressed, int frame_index)
CrumbleFloorView crumble_floor_view_
absl::Status ApplyDoorConnection(const DungeonConnectionPlan &plan)
RoomDocumentExportCallback room_document_export_callback_
absl::Status EditRoomMetadataBatch(const std::vector< RoomMetadataRequest > &requests)
RoomCompositeOutput primary_composite_output_
MinecartCanvasTool minecart_canvas_tool_
EditorContext context() const
void DrawPersistentDebugWindows(int room_id)
zelda3::SpritePreviewResourceCache sprite_preview_resources_
void SetProject(const project::YazeProject *project)
void SyncCanvasConfigFromViewerState()
std::map< int, ConnectedRoomCompositeEntry > connected_composite_outputs_
zelda3::GameData * game_data() const
std::vector< uint16_t > switch_tile_order_
bool object_interaction_enabled_
absl::Status EditRoomMetadata(int room_id, const RoomMetadataEdit &edit)
absl::StatusOr< DungeonConnectionPlan > PreviewDoorConnection(const DungeonConnectionRequest &request)
zelda3::Room * PrepareActiveRoomForCanvasFrame(int room_id)
void RefreshRomBackedState(Rom *rom, zelda3::GameData *game_data, DungeonRoomStore *rooms, int room_id)
DungeonObjectInteraction object_interaction_
uint64_t last_palette_hash_
void DrawRoomCanvasContent(const gui::CanvasRuntime &canvas_rt, zelda3::Room &room, int room_id)
double change_ping_start_time_
void ResetRoomCompositeOutputs()
void DrawCoordinateOverlayHud(int room_id)
void ClearPreviewObject()
bool room_canvas_shortcut_focus_
void TriggerCanvasPingRect(int pixel_x, int pixel_y, int pixel_w, int pixel_h)
absl::Status EditChest(int room_id, size_t index, uint8_t item_id, bool big_chest)
const project::YazeProject * project_
DoorConnectionApplyCallback door_connection_apply_callback_
void DrawCompactLayerToggles(int room_id)
int last_connected_matrix_room_id_
absl::StatusOr< DungeonRoomTransferPlan > PreviewRoomTransfer(int source_room_id, const std::string &json, const DungeonRoomTransferOptions &options)
void UpdateRoomCanvasViewport(ImVec2 viewport_size)
std::unordered_map< int, DungeonRenderingHelpers::CollisionOverlayCache > collision_overlay_cache_
gfx::Bitmap * PrepareRoomCompositeBitmap(int room_id)
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
bool track_direction_map_enabled_
void TriggerObjectChangePing(const std::vector< zelda3::RoomObject > &previous_objects, const std::vector< zelda3::RoomObject > &next_objects)
bool ValidateRoomCanvasRequest(int room_id)
gui::CanvasFrameOptions BuildRoomCanvasFrameOptions() const
DungeonRoomStore * rooms_
util::LruCache< SpritePreviewKey, CachedSpritePreview > sprite_preview_cache_
bool HasRoomCanvasShortcutFocusForFrame(int frame_index) const
absl::Status DeleteChest(int room_id, size_t index)
MetadataBatchEditCallback metadata_batch_edit_callback_
const project::YazeProject * project() const
gui::CanvasTouchHandler touch_handler_
MetadataEditCallback metadata_edit_callback_
DungeonConnectionEditorState connection_editor_state_
int room_canvas_last_draw_frame_
void ConsumePendingCanvasScroll(const gui::CanvasRuntime &canvas_rt)
void DrawDungeonCanvas(int room_id)
void SyncViewerStateFromCanvasConfig()
std::vector< ObjectRenderCache > object_render_cache_
DungeonRenderingHelpers::TrackCollisionConfig track_collision_config_
void SetRooms(DungeonRoomStore *rooms)
MinecartTrackEditorPanel * minecart_track_panel_
void HandleRoomCanvasNavigation(gui::CanvasRuntime &canvas_rt)
std::vector< ChangePingRect > change_ping_rects_
void InvalidateExternalSpriteResources()
std::map< int, RoomLayerState > room_layer_managers_
void DrawHeaderHiddenMetadataHud(int room_id)
void DrawRoomCanvasOverlays(const gui::CanvasRuntime &rt, zelda3::Room &room, int room_id)
void SetGameData(zelda3::GameData *game_data)
SelectedEntity GetSelectedEntity() const
void HandleMouseRelease()
void SetCurrentRoom(DungeonRoomStore *rooms, int room_id)
std::vector< size_t > GetSelectedObjectIndices() const
InteractionModeManager & mode_manager()
InteractionCoordinator & entity_coordinator()
Get the interaction coordinator for entity handling.
bool HasEntitySelection() const
zelda3::Room * GetIfMaterialized(int room_id)
zelda3::Room * GetIfLoaded(int room_id)
const std::vector< SelectedEntity > & GetSelectedEntities() const
TileObjectHandler & tile_handler()
void ClearAllEntitySelections()
Clear all entity selections.
void CancelCurrentMode()
Cancel current mode and return to Select.
void set_canvas_editing(bool enabled)
void set_collision_stamping(bool enabled)
bool canvas_editing() const
void Update()
Update touch state each frame.
void ProcessForCanvas(ImVec2 canvas_p0, ImVec2 canvas_sz, bool is_hovered)
Process touch gestures for the current canvas bounds.
static DimensionService & Get()
std::tuple< int, int, int, int > GetSelectionBoundsPixels(const RoomObject &obj) const
RoomLayerManager - Manages layer visibility and compositing.
uint8_t GetLayerValue() const
const std::vector< Door > & GetDoors() const
const std::vector< zelda3::Sprite > & GetSprites() const
const std::vector< RoomObject > & GetTileObjects() const
const std::vector< PotItem > & GetPotItems() const
bool SetContext(std::string_view project_path, std::string_view assets_path, std::string_view hack_name)
const AgentUITheme & GetTheme()
constexpr double kChangePingDurationSeconds
constexpr size_t kRecentRoomLimit
constexpr int kDungeonCanvasPixelSize
bool HasSameObjectIdentity(const zelda3::RoomObject &lhs, const zelda3::RoomObject &rhs)
Editors are the view controllers for the application.
void DrawDungeonRoomTransferPopup(DungeonCanvasViewer &viewer)
void EndCanvas(Canvas &canvas)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
constexpr int kNumberOfRooms
DungeonConnectionRequest request
std::array< bool, 256 > stop_tiles
std::array< bool, 256 > switch_tiles
std::array< bool, 256 > track_tiles
Represents a selected entity in the dungeon editor.
std::vector< uint16_t > minecart_sprite_ids
std::vector< uint16_t > track_stop_tiles
std::vector< uint16_t > track_tiles
std::vector< uint16_t > track_switch_tiles
Modern project structure with comprehensive settings consolidation.
DungeonOverlaySettings dungeon_overlay