## 1. Maya-style Viewport Controls - [x] 1.1 Refactor `ViewportPanel::HandleInput()` to use Alt+LMB for orbit, Alt+MMB for pan, Alt+RMB for dolly - [x] 1.2 Remove legacy input mappings (LMB orbit, MMB pan, Shift+LMB pan) from `HandleInput()` - [x] 1.3 Keep mouse scroll zoom working without Alt modifier - [x] 1.4 Add Alt key detection via `io.KeyAlt` in ImGui and ensure Alt is not consumed by ImGui menu navigation ## 2. ViewportCamera Dual-Mode Support - [x] 2.1 Add `enum class CameraMode { Free, UsdCamera }` and a `m_mode` member to `ViewportCamera` - [x] 2.2 Add `m_usdCameraPath` (SdfPath) and `m_savedFreeCameraState` struct to persist free camera state across mode switches - [x] 2.3 Add `SetUsdCamera(const UsdStageRefPtr& stage, const SdfPath& cameraPath)` method that reads UsdCamera attributes (focalLength, horizontalAperture, verticalAperture, clippingRange, projection) and world transform - [x] 2.4 Implement `ComputeUsdCameraViewMatrix()` deriving the view matrix from the UsdCamera prim's world-space transform - [x] 2.5 Implement `ComputeUsdCameraProjectionMatrix()` deriving the projection matrix from UsdCamera focalLength, aperture, and clip attributes - [x] 2.6 Modify `GetViewMatrix()` and `GetProjectionMatrix()` to dispatch based on `m_mode` (free vs USD camera) - [x] 2.7 Add `SwitchToFreeCamera()` that restores the saved free camera state - [x] 2.8 Disable orbit/pan/zoom/dolly calls when `m_mode == UsdCamera` (no-op in USD camera mode) ## 3. Camera Selector UI - [x] 3.1 Add method `FindCameraPrims(const UsdStageRefPtr& stage)` to traverse the stage and return a vector of SdfPaths for all UsdCamera-typed prims - [x] 3.2 Cache the camera list in `ViewportPanel` and invalidate on stage change - [x] 3.3 Add an ImGui combo dropdown above the viewport canvas in `ViewportPanel::Render()` with "Free Camera" as the first entry followed by discovered camera prim paths - [x] 3.4 Wire the dropdown selection to call `ViewportCamera::SetUsdCamera()` or `SwitchToFreeCamera()` - [x] 3.5 Reset the camera selector to "Free Camera" when a new stage is loaded via `ViewportPanel::SetStage()` ## 4. Frame Selected Prim - [x] 4.1 Add `m_selectedPrimPath` string member to `ViewportPanel` and a setter `SetSelectedPrimPath(const std::string&)` - [x] 4.2 Wire `Application` to call `ViewportPanel::SetSelectedPrimPath()` from the `SceneHierarchyPanel::SetOnPrimSelected()` callback - [x] 4.3 Add F key handler in `ViewportPanel::HandleInput()`: compute bounding box of the selected prim using `UsdGeomBBoxCache` and call `FrameBoundingBox` - [x] 4.4 If viewport is in USD camera mode when F is pressed, switch to free camera mode first then frame - [x] 4.5 Add A key handler in `ViewportPanel::HandleInput()`: call `FrameScene()` to frame all ## 5. Integration and Verification - [x] 5.1 Verify Maya-style Alt+button navigation works for orbit, pan, and dolly in the viewport - [x] 5.2 Verify camera selector dropdown lists free camera and all stage camera prims - [x] 5.3 Verify switching to a USD camera renders from that camera's viewpoint - [x] 5.4 Verify switching back to free camera restores the previous free camera position - [x] 5.5 Verify F key frames the selected prim and A key frames the entire stage - [x] 5.6 Build and run the application to confirm no regressions in existing viewport rendering