Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0597ae31d | |||
| 425d21db45 |
Binary file not shown.
|
After Width: | Height: | Size: 609 KiB |
+24
-2
@@ -43,6 +43,7 @@ Application::Application()
|
|||||||
, m_showViewport(true)
|
, m_showViewport(true)
|
||||||
, m_showPropertyPanel(true)
|
, m_showPropertyPanel(true)
|
||||||
, m_showTimeline(true)
|
, m_showTimeline(true)
|
||||||
|
, m_showCurveEditor(false)
|
||||||
, m_running(false) {
|
, m_running(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +79,19 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
|||||||
m_propertyPanel->SetPropertyManager(m_propertyManager.get());
|
m_propertyPanel->SetPropertyManager(m_propertyManager.get());
|
||||||
m_propertyPanel->SetCommandHistory(&m_commandHistory);
|
m_propertyPanel->SetCommandHistory(&m_commandHistory);
|
||||||
|
|
||||||
|
m_curveEditorPanel = std::make_unique<CurveEditorPanel>();
|
||||||
|
m_curveEditorPanel->SetCommandHistory(&m_commandHistory);
|
||||||
|
|
||||||
m_timelinePanel = std::make_unique<TimelinePanel>();
|
m_timelinePanel = std::make_unique<TimelinePanel>();
|
||||||
m_timelinePanel->OnTimeChanged = [this](pxr::UsdTimeCode displayTime,
|
m_timelinePanel->OnTimeChanged = [this](pxr::UsdTimeCode displayTime,
|
||||||
pxr::UsdTimeCode editTime) {
|
pxr::UsdTimeCode editTime) {
|
||||||
m_viewportPanel->SetTimeCodes(displayTime, editTime);
|
m_viewportPanel->SetTimeCodes(displayTime, editTime);
|
||||||
m_propertyPanel->SetTimeCodes(displayTime, editTime);
|
m_propertyPanel->SetTimeCodes(displayTime, editTime);
|
||||||
|
m_curveEditorPanel->SetTimeCodes(displayTime, editTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_curveEditorPanel->OnScrub = [this](double frame) {
|
||||||
|
m_timelinePanel->SetCurrentFrameExternal(frame);
|
||||||
};
|
};
|
||||||
m_timelinePanel->OnBrowseFolder = [this]() -> std::string {
|
m_timelinePanel->OnBrowseFolder = [this]() -> std::string {
|
||||||
HWND hwnd = m_imguiContext ? m_imguiContext->GetWindowHandle() : nullptr;
|
HWND hwnd = m_imguiContext ? m_imguiContext->GetWindowHandle() : nullptr;
|
||||||
@@ -101,6 +110,7 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
|||||||
[this](const std::string& path) {
|
[this](const std::string& path) {
|
||||||
m_viewportPanel->SetSelectedPrimPath(path);
|
m_viewportPanel->SetSelectedPrimPath(path);
|
||||||
m_propertyPanel->SetSelectedPrimPath(path);
|
m_propertyPanel->SetSelectedPrimPath(path);
|
||||||
|
m_curveEditorPanel->SetSelectedPrimPath(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_sceneHierarchyPanel->SetOnStageMetadataChanged(
|
m_sceneHierarchyPanel->SetOnStageMetadataChanged(
|
||||||
@@ -108,16 +118,18 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
|||||||
RefreshManagers();
|
RefreshManagers();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Single click in viewport → sync hierarchy + property panel
|
// Single click in viewport → sync hierarchy + property panel + curve editor
|
||||||
m_viewportPanel->OnPrimPicked = [this](const std::string& path) {
|
m_viewportPanel->OnPrimPicked = [this](const std::string& path) {
|
||||||
m_sceneHierarchyPanel->SetSelectedPath(path);
|
m_sceneHierarchyPanel->SetSelectedPath(path);
|
||||||
m_propertyPanel->SetSelectedPrimPath(path);
|
m_propertyPanel->SetSelectedPrimPath(path);
|
||||||
|
m_curveEditorPanel->SetSelectedPrimPath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rect drag in viewport → sync hierarchy + property panel (primary path)
|
// Rect drag in viewport → sync hierarchy + property panel + curve editor (primary)
|
||||||
m_viewportPanel->OnPrimsPickedRect = [this](const std::vector<std::string>& paths) {
|
m_viewportPanel->OnPrimsPickedRect = [this](const std::vector<std::string>& paths) {
|
||||||
m_sceneHierarchyPanel->SetSelectedPaths(paths);
|
m_sceneHierarchyPanel->SetSelectedPaths(paths);
|
||||||
m_propertyPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
m_propertyPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
||||||
|
m_curveEditorPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!m_stageManager->CreateInMemoryStage()) {
|
if (!m_stageManager->CreateInMemoryStage()) {
|
||||||
@@ -178,6 +190,7 @@ void Application::RefreshManagers() {
|
|||||||
m_viewportPanel->FrameScene();
|
m_viewportPanel->FrameScene();
|
||||||
m_propertyPanel->SetStage(stage);
|
m_propertyPanel->SetStage(stage);
|
||||||
m_timelinePanel->SetStage(stage);
|
m_timelinePanel->SetStage(stage);
|
||||||
|
m_curveEditorPanel->SetStage(stage);
|
||||||
} else {
|
} else {
|
||||||
m_layerManager->SetStage(nullptr);
|
m_layerManager->SetStage(nullptr);
|
||||||
m_propertyManager->SetStage(nullptr);
|
m_propertyManager->SetStage(nullptr);
|
||||||
@@ -185,6 +198,7 @@ void Application::RefreshManagers() {
|
|||||||
m_viewportPanel->SetStage(nullptr);
|
m_viewportPanel->SetStage(nullptr);
|
||||||
m_propertyPanel->SetStage(nullptr);
|
m_propertyPanel->SetStage(nullptr);
|
||||||
m_timelinePanel->SetStage(nullptr);
|
m_timelinePanel->SetStage(nullptr);
|
||||||
|
m_curveEditorPanel->SetStage(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +269,13 @@ void Application::RenderUI() {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_showCurveEditor) {
|
||||||
|
ImGui::SetNextWindowSize({960, 320}, ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::Begin("Curve Editor", &m_showCurveEditor, ImGuiWindowFlags_NoCollapse);
|
||||||
|
m_curveEditorPanel->Render();
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
// Capture happens after the timeline so that the "Start" button click in
|
// Capture happens after the timeline so that the "Start" button click in
|
||||||
// this frame is detected, and after the viewport has rendered the scene.
|
// this frame is detected, and after the viewport has rendered the scene.
|
||||||
if (m_timelinePanel->IsPlayblasting()) {
|
if (m_timelinePanel->IsPlayblasting()) {
|
||||||
@@ -395,6 +416,7 @@ void Application::RenderMenuBar() {
|
|||||||
ImGui::MenuItem("Viewport", nullptr, &m_showViewport);
|
ImGui::MenuItem("Viewport", nullptr, &m_showViewport);
|
||||||
ImGui::MenuItem("Property Panel", nullptr, &m_showPropertyPanel);
|
ImGui::MenuItem("Property Panel", nullptr, &m_showPropertyPanel);
|
||||||
ImGui::MenuItem("Timeline", nullptr, &m_showTimeline);
|
ImGui::MenuItem("Timeline", nullptr, &m_showTimeline);
|
||||||
|
ImGui::MenuItem("Curve Editor", nullptr, &m_showCurveEditor);
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::MenuItem("Stage Info", nullptr, &m_showStageInfo);
|
ImGui::MenuItem("Stage Info", nullptr, &m_showStageInfo);
|
||||||
ImGui::MenuItem("Demo Window", nullptr, &m_showDemoWindow);
|
ImGui::MenuItem("Demo Window", nullptr, &m_showDemoWindow);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "ViewportPanel.h"
|
#include "ViewportPanel.h"
|
||||||
#include "PropertyPanel.h"
|
#include "PropertyPanel.h"
|
||||||
#include "TimelinePanel.h"
|
#include "TimelinePanel.h"
|
||||||
|
#include "CurveEditorPanel.h"
|
||||||
#include "../core/UsdStageManager.h"
|
#include "../core/UsdStageManager.h"
|
||||||
#include "../core/LayerManager.h"
|
#include "../core/LayerManager.h"
|
||||||
#include "../core/PropertyManager.h"
|
#include "../core/PropertyManager.h"
|
||||||
@@ -59,6 +60,7 @@ private:
|
|||||||
std::unique_ptr<ViewportPanel> m_viewportPanel;
|
std::unique_ptr<ViewportPanel> m_viewportPanel;
|
||||||
std::unique_ptr<PropertyPanel> m_propertyPanel;
|
std::unique_ptr<PropertyPanel> m_propertyPanel;
|
||||||
std::unique_ptr<TimelinePanel> m_timelinePanel;
|
std::unique_ptr<TimelinePanel> m_timelinePanel;
|
||||||
|
std::unique_ptr<CurveEditorPanel> m_curveEditorPanel;
|
||||||
bool m_showDemoWindow;
|
bool m_showDemoWindow;
|
||||||
bool m_showStageInfo;
|
bool m_showStageInfo;
|
||||||
bool m_showStageEditor;
|
bool m_showStageEditor;
|
||||||
@@ -66,6 +68,7 @@ private:
|
|||||||
bool m_showViewport;
|
bool m_showViewport;
|
||||||
bool m_showPropertyPanel;
|
bool m_showPropertyPanel;
|
||||||
bool m_showTimeline;
|
bool m_showTimeline;
|
||||||
|
bool m_showCurveEditor;
|
||||||
bool m_running;
|
bool m_running;
|
||||||
|
|
||||||
MovieEncoder m_movieEncoder;
|
MovieEncoder m_movieEncoder;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,153 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../core/CommandHistory.h"
|
||||||
|
#include <pxr/usd/usd/stage.h>
|
||||||
|
#include <pxr/usd/usd/attribute.h>
|
||||||
|
#include <pxr/usd/usd/timeCode.h>
|
||||||
|
#include <pxr/usd/usd/notice.h>
|
||||||
|
#include <pxr/base/tf/weakBase.h>
|
||||||
|
#include <pxr/base/tf/notice.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace UsdLayerManager {
|
||||||
|
|
||||||
|
class CurveEditorPanel : public pxr::TfWeakBase {
|
||||||
|
public:
|
||||||
|
void SetStage(pxr::UsdStageRefPtr stage);
|
||||||
|
void SetCommandHistory(CommandHistory* history) { m_commandHistory = history; }
|
||||||
|
void SetSelectedPrimPath(const std::string& path);
|
||||||
|
void SetTimeCodes(pxr::UsdTimeCode displayTime, pxr::UsdTimeCode editTime);
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
// Fires when the user drags the time cursor; drives the Timeline panel.
|
||||||
|
std::function<void(double frame)> OnScrub;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ── Internal data ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
struct BezierKey {
|
||||||
|
double time = 0.0;
|
||||||
|
double value = 0.0;
|
||||||
|
// Tangent handles as (dt, dv) offsets from the key.
|
||||||
|
// in-handle is left of the key (dt < 0), out-handle is right (dt > 0).
|
||||||
|
double inTangentDt = -1.0, inTangentDv = 0.0;
|
||||||
|
double outTangentDt = 1.0, outTangentDv = 0.0;
|
||||||
|
bool tangentsBroken = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurveChannel {
|
||||||
|
std::string displayName;
|
||||||
|
pxr::UsdAttribute attr;
|
||||||
|
int component = -1; // -1=scalar, 0/1/2/3 = X/Y/Z/W
|
||||||
|
ImVec4 color = {1,1,1,1};
|
||||||
|
bool visible = true;
|
||||||
|
bool dirty = false;
|
||||||
|
std::vector<double> origTimes;
|
||||||
|
std::vector<double> origValues;
|
||||||
|
std::vector<BezierKey> keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class HandlePart { Key, InTangent, OutTangent };
|
||||||
|
struct SelectedHandle { int chanIdx; int keyIdx; HandlePart part; };
|
||||||
|
|
||||||
|
// ── Methods ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
void RefreshFromStage();
|
||||||
|
void FitCurveFromSamples(CurveChannel& ch);
|
||||||
|
void BakeChannelToUsd(CurveChannel& ch);
|
||||||
|
|
||||||
|
// Bezier math
|
||||||
|
double EvaluateBezier(const std::vector<BezierKey>& keys, double T) const;
|
||||||
|
void DrawBezierSegment(ImDrawList* dl, const BezierKey& k0, const BezierKey& k1,
|
||||||
|
ImVec4 color, ImVec2 canvasMin, ImVec2 canvasMax) const;
|
||||||
|
|
||||||
|
// Coordinate helpers
|
||||||
|
float TimeToX(double t, ImVec2 cMin, ImVec2 cMax) const;
|
||||||
|
float ValToY (double v, ImVec2 cMin, ImVec2 cMax) const;
|
||||||
|
double XToTime(float x, ImVec2 cMin, ImVec2 cMax) const;
|
||||||
|
double YToVal (float y, ImVec2 cMin, ImVec2 cMax) const;
|
||||||
|
ImVec2 KeyToScreen(const BezierKey& k, ImVec2 cMin, ImVec2 cMax) const;
|
||||||
|
|
||||||
|
// USD channel read/write helpers
|
||||||
|
double ReadChannelValue (const pxr::UsdAttribute& attr, int comp, double time) const;
|
||||||
|
void WriteChannelValue(const pxr::UsdAttribute& attr, int comp,
|
||||||
|
double time, double val) const;
|
||||||
|
void ClearAllTimeSamples(const pxr::UsdAttribute& attr) const;
|
||||||
|
|
||||||
|
// Rendering sub-sections
|
||||||
|
void RenderToolbar();
|
||||||
|
void RenderAttrList(float listWidth);
|
||||||
|
void RenderCanvas(ImVec2 canvasMin, ImVec2 canvasMax);
|
||||||
|
void RenderGrid(ImDrawList* dl, ImVec2 cMin, ImVec2 cMax);
|
||||||
|
void RenderTimeCursor(ImDrawList* dl, ImVec2 cMin, ImVec2 cMax);
|
||||||
|
void RenderCurve(ImDrawList* dl, CurveChannel& ch, ImVec2 cMin, ImVec2 cMax);
|
||||||
|
void HandleCanvasInput(ImVec2 cMin, ImVec2 cMax);
|
||||||
|
|
||||||
|
// Selection helpers
|
||||||
|
bool IsSelected(int chanIdx, int keyIdx, HandlePart part) const;
|
||||||
|
void Select(int chanIdx, int keyIdx, HandlePart part, bool additive);
|
||||||
|
void ClearSelection();
|
||||||
|
|
||||||
|
// Interaction helpers
|
||||||
|
void FrameAll();
|
||||||
|
void ApplyAllDirty();
|
||||||
|
void RevertAll();
|
||||||
|
void DeleteSelectedKeys();
|
||||||
|
void AddKeyAt(int chanIdx, double time, double value);
|
||||||
|
// Re-fit Catmull-Rom tangents for neighbors of a modified key
|
||||||
|
void RefitNeighborTangents(CurveChannel& ch, int keyIdx);
|
||||||
|
|
||||||
|
// ── State ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
pxr::UsdStageRefPtr m_stage;
|
||||||
|
CommandHistory* m_commandHistory = nullptr;
|
||||||
|
std::string m_selectedPrimPath;
|
||||||
|
pxr::UsdTimeCode m_displayTime = pxr::UsdTimeCode::Default();
|
||||||
|
pxr::UsdTimeCode m_editTime = pxr::UsdTimeCode::Default();
|
||||||
|
|
||||||
|
std::vector<CurveChannel> m_channels;
|
||||||
|
std::vector<SelectedHandle> m_selection;
|
||||||
|
int m_activeChannel = -1; // for double-click-to-add
|
||||||
|
|
||||||
|
bool m_needsRefresh = true;
|
||||||
|
|
||||||
|
// USD change notification
|
||||||
|
pxr::TfNotice::Key m_stageChangeKey;
|
||||||
|
void OnObjectsChanged(const pxr::UsdNotice::ObjectsChanged& notice,
|
||||||
|
const pxr::UsdStageWeakPtr& sender);
|
||||||
|
|
||||||
|
// View range
|
||||||
|
double m_viewMinTime = 0.0, m_viewMaxTime = 100.0;
|
||||||
|
double m_viewMinVal = -1.0, m_viewMaxVal = 1.0;
|
||||||
|
|
||||||
|
// Pan/zoom drag state
|
||||||
|
bool m_isPanning = false;
|
||||||
|
ImVec2 m_panLastMouse = {0,0};
|
||||||
|
double m_panMinTimeStart = 0.0, m_panMaxTimeStart = 0.0;
|
||||||
|
double m_panMinValStart = 0.0, m_panMaxValStart = 0.0;
|
||||||
|
|
||||||
|
// Drag-move state
|
||||||
|
bool m_isDragging = false;
|
||||||
|
ImVec2 m_dragStartMouse= {0,0};
|
||||||
|
double m_dragStartTime = 0.0, m_dragStartValue = 0.0;
|
||||||
|
struct KeySnapshot { int chanIdx; int keyIdx; double time; double value;
|
||||||
|
double inDt, inDv, outDt, outDv; };
|
||||||
|
std::vector<KeySnapshot> m_dragSnapshot;
|
||||||
|
|
||||||
|
// Selection box drag
|
||||||
|
bool m_isBoxSelecting = false;
|
||||||
|
ImVec2 m_boxSelectStart = {0,0};
|
||||||
|
|
||||||
|
// Scrub cursor drag
|
||||||
|
bool m_isDraggingCursor = false;
|
||||||
|
|
||||||
|
// Options
|
||||||
|
bool m_simplifyOnBake = false;
|
||||||
|
float m_simplifyTol = 0.01f;
|
||||||
|
bool m_snapToFrame = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace UsdLayerManager
|
||||||
@@ -369,6 +369,11 @@ void TimelinePanel::SetCurrentFrame(double frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelinePanel::SetCurrentFrameExternal(double frame)
|
||||||
|
{
|
||||||
|
SetCurrentFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
void TimelinePanel::NotifyTimeChanged()
|
void TimelinePanel::NotifyTimeChanged()
|
||||||
{
|
{
|
||||||
if (OnTimeChanged)
|
if (OnTimeChanged)
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ public:
|
|||||||
bool AdvancePlayblast();
|
bool AdvancePlayblast();
|
||||||
void AbortPlayblast();
|
void AbortPlayblast();
|
||||||
|
|
||||||
|
/// Drive the timeline from an external source (e.g. curve editor scrubbing).
|
||||||
|
void SetCurrentFrameExternal(double frame);
|
||||||
|
|
||||||
/// Callback set by Application so the dialog can open a native folder picker.
|
/// Callback set by Application so the dialog can open a native folder picker.
|
||||||
std::function<std::string()> OnBrowseFolder;
|
std::function<std::string()> OnBrowseFolder;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user