#pragma once #include "../core/UsdSceneRenderer.h" #include "../core/ViewportCamera.h" #include "../core/CommandHistory.h" #include "TransformManipulator.h" #include "IconManager.h" #include #include #include #include #include #include #include namespace UsdLayerManager { /// Named orthographic view directions. /// When m_orthoView != None the tile renders an orthographic camera locked to /// that world-space direction; the free-camera orbital state (center + dist) /// is reused for pan and zoom so each tile keeps an independent view. enum class OrthoView { None, ///< Not an ortho view — free camera or USD camera prim Top, Bottom, Front, Back, Left, Right, }; /// A single viewport tile. /// /// Owns its own ViewportCamera, UsdSceneRenderer, and all per-tile settings /// (grid, AA, background colour, bbox mode, render delegate). Selection state /// and the TransformManipulator are owned by the ViewportPanel container and /// passed in per frame so they can be shared across tiles. class ViewportTile { public: ViewportTile(); ~ViewportTile(); // ── Setup (called once by container) ──────────────────────────────────── void SetStage(pxr::UsdStageRefPtr stage); void SetIconManager(IconManager* icons) { m_iconManager = icons; } void SetCommandHistory(CommandHistory* h); /// displayTime — frame used for all evaluation (render, cameras, bboxes). /// editTime — frame writes are authored at (Default unless Auto-Key). void SetTimeCodes(pxr::UsdTimeCode displayTime, pxr::UsdTimeCode editTime); // ── Selection sync ─────────────────────────────────────────────────────── /// Called by the container to broadcast the authoritative selection. /// Updates the local shadow copy and pushes it into the renderer highlight. void SetSelectedPaths(const pxr::SdfPathVector& paths, const std::string& primaryPath); // ── Per-frame render ───────────────────────────────────────────────────── /// Render this tile inside an ImGui child window. /// /// @param tileIndex Unique index used to disambiguate ImGui IDs. /// @param pos Screen-space top-left of this tile's area. /// @param size Pixel dimensions of this tile's area. /// @param isFocused If true the transform gizmo renders here. /// @param manipulator Shared manipulator owned by the container. /// @param dividerActive When true a split-handle drag is active (or the /// mouse is over one), so rect-selection is suppressed. void Render(int tileIndex, ImVec2 pos, ImVec2 size, bool isFocused, TransformManipulator& manipulator, bool dividerActive = false); // ── Pick callbacks (assigned by container after construction) ──────────── std::function OnPrimPicked; std::function&)> OnPrimsPickedRect; // ── Per-frame state queries ────────────────────────────────────────────── /// True when the user clicked LMB inside this tile during the last Render. bool WasClickedThisFrame() const { return m_wasClickedThisFrame; } /// True when the mouse was hovering this tile during the last Render. bool IsHoveredThisFrame() const { return m_wasHoveredThisFrame; } // ── Forwarding accessors ───────────────────────────────────────────────── ViewportCamera& GetCamera() { return m_camera; } UsdSceneRenderer& GetRenderer() { return m_renderer; } void FrameScene(); private: // ── Render sub-functions ───────────────────────────────────────────────── pxr::GfCamera ResolveCamera(); /// Build an orthographic GfCamera from the current center/dist state. pxr::GfCamera BuildOrthoCamera() const; void HandleInput(bool isFocused, TransformManipulator& manipulator, bool dividerActive); void DrawSelectionRect(); void RenderContextMenu(int tileIndex); void RenderCompactToolbar(int tileIndex); void RenderManipulatorOverlay(TransformManipulator& manipulator); // ── Camera helpers ─────────────────────────────────────────────────────── void RefreshCameraList(); void TrySwitchToFreeCamera(); void InitCameraNavigation(); pxr::GfVec3d ComputeGizmoPivot() const; // ── Core components ────────────────────────────────────────────────────── ViewportCamera m_camera; UsdSceneRenderer m_renderer; IconManager* m_iconManager = nullptr; CommandHistory* m_commandHistory = nullptr; // ── Timeline time codes (synced by container) ──────────────────────────── pxr::UsdTimeCode m_displayTime = pxr::UsdTimeCode::Default(); pxr::UsdTimeCode m_editTime = pxr::UsdTimeCode::Default(); // ── Stage + camera list ────────────────────────────────────────────────── pxr::UsdStageRefPtr m_stage; std::vector m_cameraPaths; int m_selectedCameraIndex = 0; bool m_cameraListDirty = true; // ── Camera navigation mouse state ──────────────────────────────────────── float m_lastMouseX = 0.f; float m_lastMouseY = 0.f; bool m_isOrbiting = false; bool m_isPanning = false; bool m_isDollying = false; // ── Rect selection state ───────────────────────────────────────────────── bool m_isRectSelecting = false; bool m_rectDragStarted = false; ImVec2 m_rectAnchor = {0.f, 0.f}; ImVec2 m_rectCurrent = {0.f, 0.f}; static constexpr float kRectDragThreshold = 5.0f; // ── Viewport dimensions (updated each Render) ──────────────────────────── int m_viewWidth = 0; int m_viewHeight = 0; ImVec2 m_imageScreenPos = {0.f, 0.f}; // ── Selection shadow (synced by container) ─────────────────────────────── pxr::SdfPathVector m_selectedSdfPaths; std::string m_selectedPrimPath; // ── GfCamera cache ─────────────────────────────────────────────────────── pxr::GfCamera m_lastComputedGfCamera; bool m_hasLastGfCamera = false; // ── Free-camera saved state (before switching to a USD cam prim) ───────── pxr::GfCamera m_savedFreeCameraState; bool m_hasSavedFreeCameraState = false; // ── USD camera prim navigation state ──────────────────────────────────── bool m_isDrivingUsdCamPrim = false; pxr::SdfPath m_drivenUsdCamPath; // ── Orthographic view ──────────────────────────────────────────────────── OrthoView m_orthoView = OrthoView::None; // ── Per-frame interaction flags ────────────────────────────────────────── bool m_wasClickedThisFrame = false; bool m_wasHoveredThisFrame = false; }; } // namespace UsdLayerManager