fac4ca0c74
Render layer overrides only reached disk on an explicit File > Save -- SaveDirtyRenderLayers() was called from SaveUsdFile/SaveUsdFileAs and nowhere else. Everything a user authored after switching to a render layer (property values, shader parameters, material assignments) sat in a dirty in-memory SdfLayer marked with an orange asterisk, and a crash took the whole layer's overrides with it. Application::Update() now polls the active render layer's IsDirty() and saves it 0.5s after the user goes idle, gated on IsAnyItemActive() and the left mouse button so a slider or gizmo drag produces one write on release rather than one per frame. Polling rather than hooking CommandHistory::Push/Undo/Redo is deliberate: many of the writes this is meant to catch never build a command and author straight to the ambient edit target -- PropertyPanel's live WriteTranslate/Rotate/Scale and its generic attribute widgets, TransformManipulator's gizmo drags, and MaterialEditorPanel::RenderInputWidget's shader input writes. A command hook would have silently missed exactly the property and shader-parameter edits at issue. IsDirty() catches every path, commanded or not. Scope is the active layer only. Muted render layers still rely on SaveDirtyRenderLayers() at save time, and the root layer is never auto-written -- so the persisted active-layer choice (custom layer data on the root layer) still only survives a reopen once the stage itself is saved. Auto-writing the user's main scene file was ruled out. - SaveRenderLayerIfDirty() refreshes LayerManager after a successful save, or the cached isDirty snapshot leaves a stale asterisk in StageEditorPanel and the Scene Hierarchy sublayer list. A failed save latches the layer id so a read-only file can't spam the log twice a second. - Switching layers flushes the outgoing one, and Shutdown() flushes before the panels are destroyed, so edits inside the debounce window aren't stranded. - RefreshManagers() clears the auto-save state, whose layer ids belong to the outgoing stage. - New "Auto-save active layer" checkbox in the Render Layer panel, on by default, persisted as AutoSaveRenderLayer in preferences.ini. See docs/adr/0002-render-layer.md D9-D11 for the rationale. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
155 lines
5.8 KiB
C++
155 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include "ImGuiContext.h"
|
|
#include "IconManager.h"
|
|
#include "StageEditorPanel.h"
|
|
#include "SceneHierarchyPanel.h"
|
|
#include "RenderLayerPanel.h"
|
|
#include "ViewportPanel.h"
|
|
#include "PropertyPanel.h"
|
|
#include "TimelinePanel.h"
|
|
#include "CurveEditorPanel.h"
|
|
#include "MaterialEditorPanel.h"
|
|
#include "../core/UsdStageManager.h"
|
|
#include "../core/LayerManager.h"
|
|
#include "../core/RenderLayerManager.h"
|
|
#include "../core/PropertyManager.h"
|
|
#include "../core/MaterialManager.h"
|
|
#include "../core/CommandHistory.h"
|
|
#include "../utils/MovieEncoder.h"
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace UsdLayerManager {
|
|
|
|
/// Global (non-per-viewport) rendering preferences persisted to preferences.ini.
|
|
struct AppPreferences {
|
|
std::string renderDelegate = "HdStormRendererPlugin";
|
|
int colorCorrectionMode = 1; ///< ColorCorrectionMode cast to int (1 = sRGB)
|
|
std::string ocioDisplay;
|
|
std::string ocioView;
|
|
std::string ocioColorSpace;
|
|
std::string ocioLook;
|
|
float materialBrowserWidth = 220.0f; ///< Material Editor left-column width
|
|
float materialPreviewWidth = 320.0f; ///< Material Editor right-column width
|
|
/// When true, per-node pin display mode (Hypershade-style "show all" vs
|
|
/// "show connected only") and revealed hidden pins are authored into USD
|
|
/// customData so they survive reopening the material; when false, that
|
|
/// state is session-only.
|
|
bool keepGraphNodeViewSettingsInUsd = false;
|
|
/// Auto-save the active render layer's SdfLayer shortly after each edit.
|
|
bool autoSaveRenderLayer = true;
|
|
};
|
|
|
|
class Application {
|
|
public:
|
|
Application();
|
|
~Application();
|
|
|
|
bool Initialize(const std::string& windowTitle = "USD Layer Manager", int width = 1280, int height = 720);
|
|
void Run();
|
|
void Shutdown();
|
|
|
|
private:
|
|
void Update();
|
|
void RenderUI();
|
|
void RenderMenuBar();
|
|
void RenderStatusBar();
|
|
void RenderStageInfo();
|
|
void RefreshManagers();
|
|
|
|
// File operations
|
|
void OpenUsdFile();
|
|
void CreateNewUsdFile();
|
|
void SaveUsdFile();
|
|
void SaveUsdFileAs();
|
|
void CloseUsdFile();
|
|
|
|
// Stage editing operations
|
|
void AddReferenceToStage();
|
|
void CreatePrimOnStage(const std::string& typeName);
|
|
|
|
/// Explicitly saves every render-layer SdfLayer, since at most one is
|
|
/// ever in the stage's composition (unmuted) at a time and
|
|
/// UsdStage::Save() only walks layers currently in composition — the
|
|
/// rest would otherwise be silently dropped on save.
|
|
void SaveDirtyRenderLayers();
|
|
|
|
/// Per-frame debounce driving the active render layer's auto-save.
|
|
/// Polls SdfLayer::IsDirty() rather than hooking CommandHistory because
|
|
/// many write paths (PropertyPanel's live transform/attribute widgets,
|
|
/// TransformManipulator's gizmo drags, MaterialEditorPanel's shader input
|
|
/// widgets) author straight to the ambient edit target without going
|
|
/// through a command — a command hook would silently miss them.
|
|
void TickRenderLayerAutoSave(float deltaTime);
|
|
/// Saves the active render layer's SdfLayer if it's dirty. Returns true
|
|
/// only when a save actually happened.
|
|
bool FlushActiveRenderLayerSave();
|
|
/// Saves one render layer by identifier if it's dirty; no-op for an empty
|
|
/// id (Default active) or a layer whose previous save failed.
|
|
bool SaveRenderLayerIfDirty(const std::string& layerId);
|
|
|
|
// Playblast
|
|
void CapturePlayblastFrame();
|
|
|
|
// Preferences
|
|
void LoadPreferences();
|
|
void SavePreferences();
|
|
/// Reconcile persisted OCIO display/view names against the active config.
|
|
/// Falls back to the config defaults when a name doesn't exist, so a stale
|
|
/// or mistyped preference can't silently disable color correction.
|
|
void ValidateOcioPreferences();
|
|
void ApplyPrefsToAllViewports();
|
|
void RenderPreferencesDialog();
|
|
|
|
std::unique_ptr<ImGuiContext> m_imguiContext;
|
|
std::unique_ptr<IconManager> m_iconManager;
|
|
std::unique_ptr<UsdStageManager> m_stageManager;
|
|
std::unique_ptr<LayerManager> m_layerManager;
|
|
std::unique_ptr<RenderLayerManager> m_renderLayerManager;
|
|
std::unique_ptr<PropertyManager> m_propertyManager;
|
|
std::unique_ptr<MaterialManager> m_materialManager;
|
|
CommandHistory m_commandHistory;
|
|
std::unique_ptr<StageEditorPanel> m_stageEditorPanel;
|
|
std::unique_ptr<SceneHierarchyPanel> m_sceneHierarchyPanel;
|
|
std::unique_ptr<RenderLayerPanel> m_renderLayerPanel;
|
|
std::unique_ptr<ViewportPanel> m_viewportPanel;
|
|
std::unique_ptr<PropertyPanel> m_propertyPanel;
|
|
std::unique_ptr<TimelinePanel> m_timelinePanel;
|
|
std::unique_ptr<CurveEditorPanel> m_curveEditorPanel;
|
|
std::unique_ptr<MaterialEditorPanel> m_materialEditorPanel;
|
|
bool m_showDemoWindow;
|
|
bool m_showStageInfo;
|
|
bool m_showStageEditor;
|
|
bool m_showRenderLayerPanel;
|
|
bool m_showSceneHierarchy;
|
|
bool m_showViewport;
|
|
bool m_showPropertyPanel;
|
|
bool m_showTimeline;
|
|
bool m_showCurveEditor;
|
|
bool m_showMaterialEditor;
|
|
bool m_running;
|
|
|
|
MovieEncoder m_movieEncoder;
|
|
std::string m_viewportSettingsPath;
|
|
std::string m_prefsPath;
|
|
AppPreferences m_prefs;
|
|
bool m_showPreferences = false;
|
|
|
|
// Render-layer auto-save state (see TickRenderLayerAutoSave).
|
|
float m_renderLayerAutoSaveTimer = 0.0f;
|
|
std::string m_renderLayerAutoSaveLastActiveId;
|
|
// Identifier of a render layer whose Save() failed — retried only after the
|
|
// active layer changes, so a read-only file can't spam the log every tick.
|
|
std::string m_renderLayerAutoSaveFailedId;
|
|
|
|
// OCIO edit buffers for Preferences dialog
|
|
char m_prefOcioDisplayBuf[128] = {};
|
|
char m_prefOcioViewBuf[128] = {};
|
|
char m_prefOcioColorSpaceBuf[128] = {};
|
|
char m_prefOcioLookBuf[128] = {};
|
|
bool m_prefOcioFieldsSynced = false;
|
|
};
|
|
|
|
} // namespace UsdLayerManager
|