# USD Layer Manager

A C++17 / Windows desktop application providing a **Maya Render Layers-style** USD scene editor using **OpenUSD v25.05**, **ImGui 1.92.7** (docking branch), and **OpenGL 3.3** (via GLAD). Users can open, edit, and save USD files, manage layered stage overrides, inspect and edit prim properties, and interact with 3D scenes through a Hydra viewport.

![Screenshot](docs/icons/screenshot_01.png)

## Features

- **Layer Stack Management** — Create, reorder, mute/unmute sublayers with full undo support
- **Scene Hierarchy** — Browse prim tree with per-type SVG icons; create, delete, rename prims; add/replace references
- **Property Editor** — Maya Channel Box-style attribute editing with type-aware drag inputs, color pickers, and undoable transforms
- **3D Viewport** — Hydra rendering via `UsdImagingGLEngine` into an offscreen FBO; switchable render delegates (Storm, Embree, Arnold, Cycles); grid overlay; selection bounding boxes; camera wireframes
- **Multi-Viewport** — Single, horizontal split, vertical split, and quad layouts; per-tile camera and render settings; Space to maximize/restore
- **Camera Control** — Free orbital camera (tumble/truck/dolly) or drive from USD camera prims; auto near/far clipping; frame selection; correct camera prim orientation for Y-up and Z-up stages
- **Transform Gizmo** — Pure ImDrawList-based manipulator (translate/rotate/scale) in object or world space
- **Undo/Redo** — Full command history for prim creation/deletion, attribute edits, transform changes, and layer operations; Ctrl+Z / Ctrl+Y hotkeys; Edit menu integration
- **Multi-select** — Rectangular selection in viewport with cross-panel syncing

## Dependencies

| Dependency | Version | Notes |
|---|---|---|
| [OpenUSD](https://github.com/PixarAnimationStudios/OpenUSD) | v25.05 | Prebuilt; found via `FindOpenUSD.cmake` |
| [Dear ImGui](https://github.com/ocornut/imgui) | v1.92.7 | Docking branch; Win32 + OpenGL3 backends |
| [GLAD](https://glad.dav1d.de/) | — | OpenGL 3.3 core loader |
| Python | 3.12 | Required by OpenUSD runtime (`python312.dll`) |

### Optional Render Delegates

| Delegate | Renderer Version | Variable | Notes |
|---|---|---|---|
| **hdEmbree** | Embree 4.4.1 | `HDEMBREE_USD_ROOT` | USD build with `PXR_ENABLE_EMBREE_PLUGIN=ON`; set `EMBREE_LOCATION` if Embree DLLs are not in `HDEMBREE_USD_ROOT/bin` |
| **hdArnold** | Arnold 7.4.0 (MtoA 5.5.0) | `HDARNOLD_ROOT`, `ARNOLD_LOCATION` | [arnold-usd](https://github.com/Autodesk/arnold-usd) install dir + MtoA root for `ai.dll` |
| **hdCycles** | Cycles 5.2.0 | `WITH_CYCLES=ON` | Built from source under `third_party/cycles` via ExternalProject; requires MSVC |

All delegate paths are pre-configured in `CMakePresets.json`.

## Build

### Prerequisites

- Visual Studio 17 2022 (MSVC v143) with C++17 support
- CMake 3.20+
- Python 3.12 installed at `%LOCALAPPDATA%\Programs\Python\Python312\`

### Steps

```powershell
cmake --preset default
cmake --build build --config Release
cmake --install build --config Release
```

The installed executable lives in `install/bin/`.

**Presets** — `default` (Release + tests), `debug`, `release`, `no-tests`.

### Building with Cycles

`WITH_CYCLES=ON` is set in the default preset. The first build compiles Blender Cycles from `third_party/cycles` via ExternalProject — expect a significantly longer initial build. Subsequent builds are incremental.

Cycles runtime dependencies (`embree4.dll`, `openvdb.dll`, `OpenImageDenoise.dll`, `tbb12.dll`, etc.) are automatically deployed to the output directory by a post-build step. CRT DLLs bundled inside the Cycles install are excluded to avoid version conflicts with the app's own MSVC runtime.

### Tests

```powershell
cmake --build build --config Release
ctest --test-dir build -C Release
```

## Architecture

```
src/
├── main.cpp                  — Entry point (plugin path init, app lifecycle)
├── core/                     — USD business logic (no UI dependency)
│   ├── UsdStageManager       — Stage open/create/save/close lifecycle
│   ├── LayerManager          — Layer stack introspection and mutation
│   ├── PropertyManager       — Property read/write via edit target with undo
│   ├── CommandHistory        — Undo/redo stack for ICommand instances
│   ├── UsdSceneRenderer      — Hydra rendering + picking + overlays
│   ├── ViewportCamera        — Free / USD-camera-driven orbital camera
│   └── commands/             — ICommand subclasses for all mutable operations
│       ├── TransformCommand      — Undoable translate/rotate/scale
│       ├── CreatePrimCommand     — Undoable prim creation (with camera orientation)
│       ├── DeletePrimCommand     — Undoable prim deletion (SdfCopySpec snapshot)
│       ├── AttributeSetCommand   — Type-agnostic undoable attribute writes
│       ├── AddReferenceCommand   — Undoable reference addition
│       ├── ReplaceReferenceCommand — Undoable reference replacement
│       └── LayerCommands         — Create, remove, reorder sublayers
├── ui/                       — ImGui panels and application shell
│   ├── Application           — App shell (owns managers/panels, docking, menus)
│   ├── ImGuiContext           — Win32+OpenGL+ImGui initialization and loop
│   ├── ViewportPanel         — Viewport container (layout, divider drag, maximize)
│   ├── ViewportTile          — Single viewport tile (camera, rendering, overlays, picking)
│   ├── SceneHierarchyPanel   — Prim tree browser with context menus
│   ├── PropertyPanel         — Attribute/transform editor (channel box-style)
│   ├── LayerPanel            — Layer stack editor with modal dialogs
│   ├── TransformManipulator  — ImDrawList gizmo (move/rotate/scale)
│   └── IconManager           — SVG icon rasterization via NanoSVG
└── utils/                    — Cross-cutting utilities
    ├── Logger                — Thread-safe logging (file + console)
    ├── FileDialog            — Win32 file open/save dialogs
    ├── PathUtils             — Exe-relative path resolution
    └── GLExt                 — GLAD extension initialization
```

## Key Design Patterns

- **Command Pattern** — All mutable USD operations go through `ICommand` → `CommandHistory` for undo/redo
- **Panel-Manager Separation** — UI panels hold pointers to core managers but contain no USD layer/prim logic
- **Callback Wiring** — Cross-panel communication via `std::function` callbacks (e.g. viewport pick → hierarchy select → property panel update)
- **Render-Delegate Plugability** — `UsdSceneRenderer` can switch Hydra render plugins at runtime
- **Gizmo as 2D Overlay** — `TransformManipulator` uses pure `ImDrawList` calls (no GL resources), same approach as ImGuizmo

## Project Configuration

| Config | Purpose |
|---|---|
| `cmake/modules/FindOpenUSD.cmake` | OpenUSD SDK discovery |
| `cmake/modules/FindImgui.cmake` | ImGui source integration |
| `cmake/modules/FindGlad.cmake` | GLAD loader setup |
| `CMakePresets.json` | Build presets (VS 17 2022, x64) |
| `AGENTS.md` | AI agent build/architecture guide |
| `.kilo/` | Kilo AI configuration (commands, agents, skills) |
| `openspec/changes/` | Feature proposals and implementation tracking |

## Development Workflow

This project uses **OpenSpec** for feature development:

1. **Propose** — Create a new change under `openspec/changes/<name>/` with `proposal.md`, `design.md`, `specs/`, and `tasks.md`
2. **Implement** — Work through checkbox-tracked tasks in `tasks.md`
3. **Archive** — Move completed changes to `openspec/archive/` when done

Use Kilo's `openspec-*` skills to streamline this workflow.

## Runtime Requirements

- **Python 3.12** — OpenUSD requires `python312.dll` at runtime. CMake copies it to the output directory via `POST_BUILD` commands.
- **USD Plugin Path** — The app scans `<exe_dir>/usd/` for `plugInfo.json` and registers plugins via `pxr::PlugRegistry`.
- **Render delegate DLLs** — hdEmbree, hdArnold, and hdCycles each bring their own runtime dependencies (Embree, Arnold SDK, Cycles libs). CMake `POST_BUILD` steps deploy all required DLLs next to the executable automatically.

## Contributing

Before writing any OpenUSD API call, verify the API exists in the actual SDK:

```powershell
findstr /r /s "FunctionName" third_party\OpenUSD_v25.05\include\
```

Always build and install before running tests:

```powershell
cmake --build build --config Release
cmake --install build --config Release
ctest --test-dir build -C Release
```

## License

See [LICENSE](LICENSE) file for details.