Add global Preferences dialog and per-viewport render delegate
Preferences (Edit > Preferences, tabbed General/Animation/Viewport): - Viewport tab: Default Render Delegate and Color Correction settings - Persisted to %APPDATA%\UsdLayerManager\preferences.ini - Render delegate: startup default only (not live-applied to running tiles) - Color correction: global, applied live to all viewports on change Render delegate per-viewport: - Each tile toolbar switches its own delegate independently - Saved per-tile in viewport_settings.ini; restored on next launch - Tiles with no saved delegate get the pref default on startup Color correction global: - Removed from gear popup; lives in Preferences > Viewport only - Applied to all tiles on init and on live change from Preferences Fix InitRenderer always applying m_currentRendererPlugin when set, rather than skipping when UsdImagingGLEngine auto-selects a default. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+244
-1
@@ -2,6 +2,7 @@
|
||||
#include "../utils/Logger.h"
|
||||
#include "../utils/FileDialog.h"
|
||||
#include "../utils/PathUtils.h"
|
||||
#include "../utils/OcioConfigParser.h"
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usd/references.h>
|
||||
#include <pxr/usd/sdf/path.h>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <imgui_internal.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -132,6 +134,7 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_curveEditorPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
||||
};
|
||||
|
||||
|
||||
if (!m_stageManager->CreateInMemoryStage()) {
|
||||
LOG_ERROR("Failed to create default in-memory stage");
|
||||
} else {
|
||||
@@ -150,13 +153,21 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
}
|
||||
}
|
||||
|
||||
// Load per-viewport settings (render delegate, grid, AA, etc.) from AppData.
|
||||
// Load per-viewport settings and global preferences from AppData.
|
||||
if (const char* appData = getenv("APPDATA")) {
|
||||
namespace fs = std::filesystem;
|
||||
fs::path dir = fs::path(appData) / "UsdLayerManager";
|
||||
fs::create_directories(dir);
|
||||
m_viewportSettingsPath = (dir / "viewport_settings.ini").string();
|
||||
m_prefsPath = (dir / "preferences.ini").string();
|
||||
m_viewportPanel->LoadSettings(m_viewportSettingsPath);
|
||||
LoadPreferences();
|
||||
// Apply pref delegate only to tiles that have no saved delegate.
|
||||
m_viewportPanel->ApplyDefaultDelegate(m_prefs.renderDelegate);
|
||||
// Color correction is always global — apply to all tiles.
|
||||
m_viewportPanel->ApplyGlobalColorCorrection(
|
||||
m_prefs.colorCorrectionMode, m_prefs.ocioDisplay,
|
||||
m_prefs.ocioView, m_prefs.ocioColorSpace, m_prefs.ocioLook);
|
||||
}
|
||||
|
||||
LOG_INFO("Application initialized successfully");
|
||||
@@ -178,6 +189,8 @@ void Application::Run() {
|
||||
void Application::Shutdown() {
|
||||
if (m_viewportPanel && !m_viewportSettingsPath.empty())
|
||||
m_viewportPanel->SaveSettings(m_viewportSettingsPath);
|
||||
if (!m_prefsPath.empty())
|
||||
SavePreferences();
|
||||
|
||||
m_viewportPanel.reset();
|
||||
m_sceneHierarchyPanel.reset();
|
||||
@@ -300,6 +313,9 @@ void Application::RenderUI() {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (m_showPreferences)
|
||||
RenderPreferencesDialog();
|
||||
|
||||
// Capture happens after the timeline so that the "Start" button click in
|
||||
// this frame is detected, and after the viewport has rendered the scene.
|
||||
if (m_timelinePanel->IsPlayblasting()) {
|
||||
@@ -346,6 +362,229 @@ void Application::RenderStatusBar() {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Global preferences persistence
|
||||
// ---------------------------------------------------------------------------
|
||||
void Application::LoadPreferences()
|
||||
{
|
||||
std::ifstream f(m_prefsPath);
|
||||
if (!f) return;
|
||||
std::string line;
|
||||
while (std::getline(f, line)) {
|
||||
if (!line.empty() && line.back() == '\r') line.pop_back();
|
||||
if (line.empty() || line.front() == '#' || line.front() == '[') continue;
|
||||
size_t eq = line.find('=');
|
||||
if (eq == std::string::npos) continue;
|
||||
std::string key = line.substr(0, eq);
|
||||
std::string val = line.substr(eq + 1);
|
||||
if (key == "RenderDelegate") m_prefs.renderDelegate = val;
|
||||
else if (key == "ColorCorrectionMode")
|
||||
m_prefs.colorCorrectionMode = [&]{ try { return std::stoi(val); } catch(...){ return 1; } }();
|
||||
else if (key == "OcioDisplay") m_prefs.ocioDisplay = val;
|
||||
else if (key == "OcioView") m_prefs.ocioView = val;
|
||||
else if (key == "OcioColorSpace") m_prefs.ocioColorSpace = val;
|
||||
else if (key == "OcioLook") m_prefs.ocioLook = val;
|
||||
}
|
||||
}
|
||||
|
||||
void Application::SavePreferences()
|
||||
{
|
||||
std::ofstream f(m_prefsPath);
|
||||
if (!f) return;
|
||||
f << "[Preferences]\n";
|
||||
f << "RenderDelegate=" << m_prefs.renderDelegate << "\n";
|
||||
f << "ColorCorrectionMode=" << m_prefs.colorCorrectionMode << "\n";
|
||||
f << "OcioDisplay=" << m_prefs.ocioDisplay << "\n";
|
||||
f << "OcioView=" << m_prefs.ocioView << "\n";
|
||||
f << "OcioColorSpace=" << m_prefs.ocioColorSpace << "\n";
|
||||
f << "OcioLook=" << m_prefs.ocioLook << "\n";
|
||||
}
|
||||
|
||||
void Application::ApplyPrefsToAllViewports()
|
||||
{
|
||||
if (!m_viewportPanel) return;
|
||||
m_viewportPanel->ApplyGlobalColorCorrection(
|
||||
m_prefs.colorCorrectionMode,
|
||||
m_prefs.ocioDisplay,
|
||||
m_prefs.ocioView,
|
||||
m_prefs.ocioColorSpace,
|
||||
m_prefs.ocioLook);
|
||||
}
|
||||
|
||||
void Application::RenderPreferencesDialog()
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(520, 400), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(),
|
||||
ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||
if (!ImGui::Begin("Preferences", &m_showPreferences,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
bool ccChanged = false;
|
||||
|
||||
if (ImGui::BeginTabBar("PrefTabs")) {
|
||||
|
||||
// ── General ─────────────────────────────────────────────────────────
|
||||
if (ImGui::BeginTabItem("General")) {
|
||||
ImGui::Spacing();
|
||||
ImGui::TextDisabled("No general settings yet.");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// ── Animation ───────────────────────────────────────────────────────
|
||||
if (ImGui::BeginTabItem("Animation")) {
|
||||
ImGui::Spacing();
|
||||
ImGui::TextDisabled("No animation settings yet.");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// ── Viewport ────────────────────────────────────────────────────────
|
||||
if (ImGui::BeginTabItem("Viewport")) {
|
||||
ImGui::Spacing();
|
||||
|
||||
// Render Delegate default — applied to viewports with no saved delegate on startup.
|
||||
// Each viewport's toolbar controls its delegate independently after load.
|
||||
ImGui::SeparatorText("Default Render Delegate");
|
||||
ImGui::TextDisabled("Applied to viewports with no saved setting on startup.");
|
||||
ImGui::Spacing();
|
||||
auto plugins = UsdSceneRenderer::GetRendererPlugins();
|
||||
pxr::TfToken curId(m_prefs.renderDelegate);
|
||||
for (const auto& pluginId : plugins) {
|
||||
std::string name = UsdSceneRenderer::GetRendererDisplayName(pluginId);
|
||||
if (name.empty()) name = pluginId.GetString();
|
||||
bool sel = (pluginId == curId);
|
||||
if (ImGui::RadioButton(name.c_str(), sel))
|
||||
m_prefs.renderDelegate = pluginId.GetString();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// Color Correction
|
||||
ImGui::SeparatorText("Color Correction");
|
||||
|
||||
auto ccItem = [&](const char* label, int mode) {
|
||||
if (ImGui::RadioButton(label, m_prefs.colorCorrectionMode == mode)) {
|
||||
m_prefs.colorCorrectionMode = mode;
|
||||
m_prefOcioFieldsSynced = false;
|
||||
ccChanged = true;
|
||||
}
|
||||
};
|
||||
ccItem("Disabled", 0);
|
||||
ccItem("sRGB", 1);
|
||||
ccItem("OpenColorIO", 2);
|
||||
|
||||
if (m_prefs.colorCorrectionMode == 2) {
|
||||
ImGui::Spacing();
|
||||
const OcioConfig& ocfg = GetCurrentOcioConfig();
|
||||
|
||||
if (!m_prefOcioFieldsSynced) {
|
||||
std::string disp = m_prefs.ocioDisplay.empty() ? ocfg.defaultDisplay : m_prefs.ocioDisplay;
|
||||
std::string view = m_prefs.ocioView.empty() ? ocfg.defaultView : m_prefs.ocioView;
|
||||
strncpy(m_prefOcioDisplayBuf, disp.c_str(), 127);
|
||||
strncpy(m_prefOcioViewBuf, view.c_str(), 127);
|
||||
strncpy(m_prefOcioColorSpaceBuf, m_prefs.ocioColorSpace.c_str(), 127);
|
||||
strncpy(m_prefOcioLookBuf, m_prefs.ocioLook.c_str(), 127);
|
||||
if (m_prefs.ocioDisplay.empty()) m_prefs.ocioDisplay = disp;
|
||||
if (m_prefs.ocioView.empty()) m_prefs.ocioView = view;
|
||||
m_prefOcioFieldsSynced = true;
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(280.f);
|
||||
|
||||
if (ImGui::BeginCombo("Display##pref", m_prefOcioDisplayBuf)) {
|
||||
for (const auto& d : ocfg.displays) {
|
||||
bool sel = (d == m_prefOcioDisplayBuf);
|
||||
if (ImGui::Selectable(d.c_str(), sel)) {
|
||||
strncpy(m_prefOcioDisplayBuf, d.c_str(), 127);
|
||||
m_prefs.ocioDisplay = d;
|
||||
auto vit = ocfg.views.find(d);
|
||||
if (vit != ocfg.views.end() && !vit->second.empty()) {
|
||||
strncpy(m_prefOcioViewBuf, vit->second[0].c_str(), 127);
|
||||
m_prefs.ocioView = vit->second[0];
|
||||
}
|
||||
ccChanged = true;
|
||||
}
|
||||
if (sel) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
{
|
||||
static const std::vector<std::string> kEmpty;
|
||||
auto vit = ocfg.views.find(std::string(m_prefOcioDisplayBuf));
|
||||
const auto& views = (vit != ocfg.views.end()) ? vit->second : kEmpty;
|
||||
if (ImGui::BeginCombo("View##pref", m_prefOcioViewBuf)) {
|
||||
for (const auto& v : views) {
|
||||
bool sel = (v == m_prefOcioViewBuf);
|
||||
if (ImGui::Selectable(v.c_str(), sel)) {
|
||||
strncpy(m_prefOcioViewBuf, v.c_str(), 127);
|
||||
m_prefs.ocioView = v;
|
||||
ccChanged = true;
|
||||
}
|
||||
if (sel) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Color Space##pref",
|
||||
m_prefOcioColorSpaceBuf[0] ? m_prefOcioColorSpaceBuf : "(default)")) {
|
||||
if (ImGui::Selectable("(default)", m_prefOcioColorSpaceBuf[0] == '\0')) {
|
||||
m_prefOcioColorSpaceBuf[0] = '\0';
|
||||
m_prefs.ocioColorSpace.clear();
|
||||
ccChanged = true;
|
||||
}
|
||||
if (m_prefOcioColorSpaceBuf[0] == '\0') ImGui::SetItemDefaultFocus();
|
||||
for (const auto& cs : ocfg.colorSpaces) {
|
||||
bool sel = (cs == m_prefOcioColorSpaceBuf);
|
||||
if (ImGui::Selectable(cs.c_str(), sel)) {
|
||||
strncpy(m_prefOcioColorSpaceBuf, cs.c_str(), 127);
|
||||
m_prefs.ocioColorSpace = cs;
|
||||
ccChanged = true;
|
||||
}
|
||||
if (sel) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Look##pref",
|
||||
m_prefOcioLookBuf[0] ? m_prefOcioLookBuf : "(none)")) {
|
||||
if (ImGui::Selectable("(none)", m_prefOcioLookBuf[0] == '\0')) {
|
||||
m_prefOcioLookBuf[0] = '\0';
|
||||
m_prefs.ocioLook.clear();
|
||||
ccChanged = true;
|
||||
}
|
||||
if (m_prefOcioLookBuf[0] == '\0') ImGui::SetItemDefaultFocus();
|
||||
for (const auto& look : ocfg.looks) {
|
||||
bool sel = (look == m_prefOcioLookBuf);
|
||||
if (ImGui::Selectable(look.c_str(), sel)) {
|
||||
strncpy(m_prefOcioLookBuf, look.c_str(), 127);
|
||||
m_prefs.ocioLook = look;
|
||||
ccChanged = true;
|
||||
}
|
||||
if (sel) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
if (ccChanged)
|
||||
ApplyPrefsToAllViewports();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void Application::RenderMenuBar() {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
@@ -403,6 +642,10 @@ void Application::RenderMenuBar() {
|
||||
m_commandHistory.Redo();
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Preferences..."))
|
||||
m_showPreferences = true;
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user