Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43c70be574 | |||
| 2a8534eda7 |
@@ -10,9 +10,10 @@ A C++17 / Windows desktop application providing a **Maya Render Layers-style** U
|
|||||||
- **Scene Hierarchy** — Browse prim tree with per-type SVG icons; create, delete, rename prims; add/replace references
|
- **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
|
- **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; grid overlay; selection bounding boxes; camera wireframes
|
- **3D Viewport** — Hydra rendering via `UsdImagingGLEngine` into an offscreen FBO; switchable render delegates; grid overlay; selection bounding boxes; camera wireframes
|
||||||
- **Camera Control** — Free orbital camera (tumble/truck/dolly) or drive from USD camera prims; auto near/far clipping; frame selection
|
- **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
|
- **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
|
- **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
|
- **Multi-select** — Rectangular selection in viewport with cross-panel syncing
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
@@ -59,15 +60,23 @@ src/
|
|||||||
├── core/ — USD business logic (no UI dependency)
|
├── core/ — USD business logic (no UI dependency)
|
||||||
│ ├── UsdStageManager — Stage open/create/save/close lifecycle
|
│ ├── UsdStageManager — Stage open/create/save/close lifecycle
|
||||||
│ ├── LayerManager — Layer stack introspection and mutation
|
│ ├── LayerManager — Layer stack introspection and mutation
|
||||||
│ ├── PropertyManager — Property read/write via edit target
|
│ ├── PropertyManager — Property read/write via edit target with undo
|
||||||
│ ├── CommandHistory — Undo/redo stack for ICommand instances
|
│ ├── CommandHistory — Undo/redo stack for ICommand instances
|
||||||
│ ├── UsdSceneRenderer — Hydra rendering + picking + overlays
|
│ ├── UsdSceneRenderer — Hydra rendering + picking + overlays
|
||||||
│ ├── ViewportCamera — Free / USD-camera-driven orbital camera
|
│ ├── ViewportCamera — Free / USD-camera-driven orbital camera
|
||||||
│ └── commands/ — ICommand subclasses for all mutable operations
|
│ └── 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
|
├── ui/ — ImGui panels and application shell
|
||||||
│ ├── Application — App shell (owns managers/panels, docking, menus)
|
│ ├── Application — App shell (owns managers/panels, docking, menus)
|
||||||
│ ├── ImGuiContext — Win32+OpenGL+ImGui initialization and loop
|
│ ├── ImGuiContext — Win32+OpenGL+ImGui initialization and loop
|
||||||
│ ├── ViewportPanel — 3D viewport with toolbar, picking, camera
|
│ ├── ViewportPanel — Viewport container (layout, divider drag, maximize)
|
||||||
|
│ ├── ViewportTile — Single viewport tile (camera, rendering, overlays, picking)
|
||||||
│ ├── SceneHierarchyPanel — Prim tree browser with context menus
|
│ ├── SceneHierarchyPanel — Prim tree browser with context menus
|
||||||
│ ├── PropertyPanel — Attribute/transform editor (channel box-style)
|
│ ├── PropertyPanel — Attribute/transform editor (channel box-style)
|
||||||
│ ├── LayerPanel — Layer stack editor with modal dialogs
|
│ ├── LayerPanel — Layer stack editor with modal dialogs
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
## 4. Attribute Edit Commands
|
## 4. Attribute Edit Commands
|
||||||
|
|
||||||
- [x] 4.1 Create `src/core/commands/AttributeSetCommand.h/.cpp` — stores `std::string description`, `std::function<void()> executeFunc`, `std::function<void()> undoFunc`; captures old value before set using `UsdAttribute::Get<T>` at the call site
|
- [x] 4.1 Create `src/core/commands/AttributeSetCommand.h/.cpp` — stores `std::string description`, `std::function<void()> executeFunc`, `std::function<void()> undoFunc`; captures old value before set using `UsdAttribute::Get<T>` at the call site
|
||||||
- [ ] 4.2 Modify `PropertyManager::SetPropertyValue` and `SetPropertyValueInLayer` — read old value, construct `AttributeSetCommand` with closures for old/new applies, push to `CommandHistory`
|
- [x] 4.2 Modify `PropertyManager::SetPropertyValue` and `SetPropertyValueInLayer` — read old value, construct `AttributeSetCommand` with closures for old/new applies, push to `CommandHistory`
|
||||||
|
|
||||||
## 5. Layer Operation Commands
|
## 5. Layer Operation Commands
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "PropertyManager.h"
|
#include "PropertyManager.h"
|
||||||
#include "LayerManager.h"
|
#include "LayerManager.h"
|
||||||
|
#include "CommandHistory.h"
|
||||||
|
#include "commands/AttributeSetCommand.h"
|
||||||
#include "../utils/Logger.h"
|
#include "../utils/Logger.h"
|
||||||
#include <pxr/usd/usd/prim.h>
|
#include <pxr/usd/usd/prim.h>
|
||||||
#include <pxr/usd/usd/primRange.h>
|
#include <pxr/usd/usd/primRange.h>
|
||||||
@@ -123,17 +125,51 @@ bool PropertyManager::SetPropertyValue(const std::string& primPath,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a current layer is set, create an edit context to target it
|
// Capture old value for undo
|
||||||
try {
|
PropertyValue oldValue = ExtractValue(attr);
|
||||||
if (m_currentLayer) {
|
SdfLayerHandle targetLayer = m_currentLayer ? m_currentLayer : m_stage->GetEditTarget().GetLayer();
|
||||||
UsdEditContext editCtx(m_stage, m_currentLayer);
|
|
||||||
return ApplyValue(attr, value);
|
// Create command with closures that capture old/new values and layer context
|
||||||
} else {
|
if (m_commandHistory) {
|
||||||
return ApplyValue(attr, value);
|
auto executeFunc = [this, primPath, propName, value, targetLayer]() {
|
||||||
|
UsdPrim p = GetPrim(primPath);
|
||||||
|
if (!p.IsValid()) return;
|
||||||
|
UsdAttribute a = p.GetAttribute(TfToken(propName));
|
||||||
|
if (!a.IsValid()) return;
|
||||||
|
|
||||||
|
UsdEditContext editCtx(m_stage, targetLayer);
|
||||||
|
ApplyValue(a, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto undoFunc = [this, primPath, propName, oldValue, targetLayer]() {
|
||||||
|
UsdPrim p = GetPrim(primPath);
|
||||||
|
if (!p.IsValid()) return;
|
||||||
|
UsdAttribute a = p.GetAttribute(TfToken(propName));
|
||||||
|
if (!a.IsValid()) return;
|
||||||
|
|
||||||
|
UsdEditContext editCtx(m_stage, targetLayer);
|
||||||
|
ApplyValue(a, oldValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string description = "Set " + propName + " on " + primPath;
|
||||||
|
m_commandHistory->Push(std::make_unique<AttributeSetCommand>(
|
||||||
|
description, executeFunc, undoFunc
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Fallback: apply directly without undo support
|
||||||
|
try {
|
||||||
|
if (m_currentLayer) {
|
||||||
|
UsdEditContext editCtx(m_stage, m_currentLayer);
|
||||||
|
return ApplyValue(attr, value);
|
||||||
|
} else {
|
||||||
|
return ApplyValue(attr, value);
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR(std::string("Failed to set property: ") + e.what());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
|
||||||
LOG_ERROR(std::string("Failed to set property: ") + e.what());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,12 +183,47 @@ bool PropertyManager::SetPropertyValueInLayer(const std::string& primPath,
|
|||||||
UsdAttribute attr = prim.GetAttribute(TfToken(propName));
|
UsdAttribute attr = prim.GetAttribute(TfToken(propName));
|
||||||
if (!attr.IsValid()) return false;
|
if (!attr.IsValid()) return false;
|
||||||
|
|
||||||
try {
|
// Capture old value for undo
|
||||||
UsdEditContext editCtx(m_stage, layer);
|
PropertyValue oldValue = ExtractValue(attr);
|
||||||
return ApplyValue(attr, value);
|
|
||||||
} catch (const std::exception& e) {
|
// Create command with closures that capture old/new values and layer context
|
||||||
LOG_ERROR(std::string("Failed to set property: ") + e.what());
|
if (m_commandHistory) {
|
||||||
return false;
|
auto executeFunc = [this, primPath, propName, value, layer]() {
|
||||||
|
UsdPrim p = GetPrim(primPath);
|
||||||
|
if (!p.IsValid()) return;
|
||||||
|
UsdAttribute a = p.GetAttribute(TfToken(propName));
|
||||||
|
if (!a.IsValid()) return;
|
||||||
|
|
||||||
|
UsdEditContext editCtx(m_stage, layer);
|
||||||
|
ApplyValue(a, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto undoFunc = [this, primPath, propName, oldValue, layer]() {
|
||||||
|
UsdPrim p = GetPrim(primPath);
|
||||||
|
if (!p.IsValid()) return;
|
||||||
|
UsdAttribute a = p.GetAttribute(TfToken(propName));
|
||||||
|
if (!a.IsValid()) return;
|
||||||
|
|
||||||
|
UsdEditContext editCtx(m_stage, layer);
|
||||||
|
ApplyValue(a, oldValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string layerName = layer ? LayerManager::ExtractDisplayName(layer->GetIdentifier()) : "default";
|
||||||
|
std::string description = "Set " + propName + " on " + primPath + " in " + layerName;
|
||||||
|
m_commandHistory->Push(std::make_unique<AttributeSetCommand>(
|
||||||
|
description, executeFunc, undoFunc
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Fallback: apply directly without undo support
|
||||||
|
try {
|
||||||
|
UsdEditContext editCtx(m_stage, layer);
|
||||||
|
return ApplyValue(attr, value);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR(std::string("Failed to set property: ") + e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ PXR_NAMESPACE_USING_DIRECTIVE
|
|||||||
|
|
||||||
namespace UsdLayerManager {
|
namespace UsdLayerManager {
|
||||||
|
|
||||||
|
class CommandHistory;
|
||||||
|
|
||||||
using PropertyValue = std::variant<
|
using PropertyValue = std::variant<
|
||||||
bool, int, float, double, std::string,
|
bool, int, float, double, std::string,
|
||||||
pxr::GfVec3f, pxr::GfVec3d
|
pxr::GfVec3f, pxr::GfVec3d
|
||||||
@@ -35,6 +37,7 @@ public:
|
|||||||
|
|
||||||
void SetStage(UsdStageRefPtr stage);
|
void SetStage(UsdStageRefPtr stage);
|
||||||
void SetCurrentLayer(const SdfLayerHandle& layer);
|
void SetCurrentLayer(const SdfLayerHandle& layer);
|
||||||
|
void SetCommandHistory(CommandHistory* history) { m_commandHistory = history; }
|
||||||
SdfLayerHandle GetCurrentLayer() const { return m_currentLayer; }
|
SdfLayerHandle GetCurrentLayer() const { return m_currentLayer; }
|
||||||
|
|
||||||
// Prim properties
|
// Prim properties
|
||||||
@@ -61,6 +64,7 @@ private:
|
|||||||
|
|
||||||
UsdStageRefPtr m_stage;
|
UsdStageRefPtr m_stage;
|
||||||
SdfLayerHandle m_currentLayer;
|
SdfLayerHandle m_currentLayer;
|
||||||
|
CommandHistory* m_commandHistory = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace UsdLayerManager
|
} // namespace UsdLayerManager
|
||||||
@@ -56,6 +56,7 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
|||||||
m_stageManager = std::make_unique<UsdStageManager>();
|
m_stageManager = std::make_unique<UsdStageManager>();
|
||||||
m_layerManager = std::make_unique<LayerManager>();
|
m_layerManager = std::make_unique<LayerManager>();
|
||||||
m_propertyManager = std::make_unique<PropertyManager>();
|
m_propertyManager = std::make_unique<PropertyManager>();
|
||||||
|
m_propertyManager->SetCommandHistory(&m_commandHistory);
|
||||||
m_layerPanel = std::make_unique<LayerPanel>();
|
m_layerPanel = std::make_unique<LayerPanel>();
|
||||||
m_layerPanel->SetLayerManager(m_layerManager.get());
|
m_layerPanel->SetLayerManager(m_layerManager.get());
|
||||||
m_layerPanel->SetCommandHistory(&m_commandHistory);
|
m_layerPanel->SetCommandHistory(&m_commandHistory);
|
||||||
|
|||||||
Reference in New Issue
Block a user