#pragma once #include "../core/CommandHistory.h" #include #include #include #include #include #include #include #include #include #include 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 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 origTimes; std::vector origValues; std::vector 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& 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); void RefitNeighborTangents(CurveChannel& ch, int keyIdx); // Bezier metadata persistence (stored in prim customData["curveEditor"]) static std::string ChannelMetadataKey(const CurveChannel& ch); bool SaveBezierToMetadata(const pxr::UsdPrim& prim, const CurveChannel& ch) const; bool SaveBezierToMetadata(const pxr::UsdPrim& prim, const std::string& channelKey, const std::vector& keys) const; bool LoadBezierFromMetadata(const pxr::UsdPrim& prim, CurveChannel& ch) const; // ── 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 m_channels; std::vector m_selection; int m_activeChannel = -1; // for double-click-to-add bool m_needsRefresh = true; bool m_suppressNotice = false; // set during bake writes to silence OnObjectsChanged // 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 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