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:
2026-06-28 11:43:32 +08:00
parent b02a736da0
commit cb0d72d980
8 changed files with 376 additions and 216 deletions
+15 -13
View File
@@ -547,23 +547,25 @@ void UsdSceneRenderer::InitRenderer() {
if (!hasCycles)
LOG_WARNING("HdCyclesPlugin not available (see startup log for DLL load errors).");
pxr::TfToken currentPlugin = m_renderer->GetCurrentRendererId();
if (currentPlugin.IsEmpty() && !plugins.empty()) {
// Apply the requested plugin. m_currentRendererPlugin is set from global
// preferences before InitRenderer runs; always honour it rather than
// checking whether the engine already chose something by default.
if (!m_currentRendererPlugin.IsEmpty()) {
pxr::TfToken cur = m_renderer->GetCurrentRendererId();
if (cur != m_currentRendererPlugin)
m_renderer->SetRendererPlugin(m_currentRendererPlugin);
} else if (!plugins.empty()) {
// Fallback heuristic: prefer Storm/GL
pxr::TfToken best;
// If a plugin was previously selected, honour it
if (!m_currentRendererPlugin.IsEmpty()) {
best = m_currentRendererPlugin;
} else {
for (const auto& p : plugins) {
std::string n(p.GetText());
if (n.find("Storm") != std::string::npos ||
n.find("GL") != std::string::npos) { best = p; break; }
}
if (best.IsEmpty()) best = plugins[0];
for (const auto& p : plugins) {
std::string n(p.GetText());
if (n.find("Storm") != std::string::npos ||
n.find("GL") != std::string::npos) { best = p; break; }
}
if (best.IsEmpty()) best = plugins[0];
m_renderer->SetRendererPlugin(best);
LOG_INFO("Selected renderer: " + std::string(m_renderer->GetCurrentRendererId().GetText()));
}
LOG_INFO("Selected renderer: " + std::string(m_renderer->GetCurrentRendererId().GetText()));
// Enable AOV "color" (matches stageView._handleRendererChanged)
m_renderer->SetRendererAov(pxr::TfToken("color"));
+1 -1
View File
@@ -313,7 +313,7 @@ private:
pxr::UsdStageRefPtr m_stage;
std::shared_ptr<pxr::UsdImagingGLEngine> m_renderer;
pxr::TfToken m_currentRendererPlugin; ///< Active plugin ID (empty = default)
pxr::TfToken m_currentRendererPlugin; ///< empty = use Storm/GL heuristic on init
pxr::GlfDrawTargetRefPtr m_drawTarget;
pxr::UsdImagingGLRenderParams m_renderParams;
+244 -1
View File
@@ -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();
}
}
+36 -10
View File
@@ -18,15 +18,25 @@
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;
};
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();
@@ -34,21 +44,27 @@ private:
void RenderStatusBar();
void RenderStageInfo();
void RefreshManagers();
// File operations
void OpenUsdFile();
void CreateNewUsdFile(); // creates fresh in-memory stage
void CreateNewUsdFile();
void SaveUsdFile();
void SaveUsdFileAs();
void CloseUsdFile(); // closes file-backed stage, falls back to default stage
void CloseUsdFile();
// Stage editing operations (also exposed via Stage menu)
// Stage editing operations
void AddReferenceToStage();
void CreatePrimOnStage(const std::string& typeName);
// Playblast — called each frame while a capture is in progress.
// Playblast
void CapturePlayblastFrame();
// Preferences
void LoadPreferences();
void SavePreferences();
void ApplyPrefsToAllViewports();
void RenderPreferencesDialog();
std::unique_ptr<ImGuiContext> m_imguiContext;
std::unique_ptr<IconManager> m_iconManager;
std::unique_ptr<UsdStageManager> m_stageManager;
@@ -71,8 +87,18 @@ private:
bool m_showCurveEditor;
bool m_running;
MovieEncoder m_movieEncoder;
std::string m_viewportSettingsPath; ///< %APPDATA%\UsdLayerManager\viewport_settings.ini
MovieEncoder m_movieEncoder;
std::string m_viewportSettingsPath;
std::string m_prefsPath;
AppPreferences m_prefs;
bool m_showPreferences = false;
// 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
+41 -22
View File
@@ -67,6 +67,7 @@ void ViewportPanel::WireCallbacks(int i)
BroadcastSelection();
if (OnPrimsPickedRect) OnPrimsPickedRect(paths);
};
}
// ---------------------------------------------------------------------------
@@ -610,6 +611,34 @@ void ViewportPanel::Render(bool* p_open)
ImGui::PopStyleVar(); // outer WindowPadding
}
// ---------------------------------------------------------------------------
// Global preferences
// ---------------------------------------------------------------------------
void ViewportPanel::ApplyDefaultDelegate(const std::string& delegate)
{
if (delegate.empty()) return;
for (auto& tile : m_tiles) {
if (tile->GetRenderer().GetCurrentRendererId().IsEmpty())
tile->GetRenderer().SetRendererPlugin(pxr::TfToken(delegate));
}
}
void ViewportPanel::ApplyGlobalColorCorrection(int ccMode,
const std::string& ocioDisplay,
const std::string& ocioView,
const std::string& ocioColorSpace,
const std::string& ocioLook)
{
for (auto& tile : m_tiles) {
auto& r = tile->GetRenderer();
r.SetColorCorrectionMode(static_cast<ColorCorrectionMode>(ccMode));
r.SetOcioDisplay(ocioDisplay);
r.SetOcioView(ocioView);
r.SetOcioColorSpace(ocioColorSpace);
r.SetOcioLook(ocioLook);
}
}
// ---------------------------------------------------------------------------
// Settings persistence
// ---------------------------------------------------------------------------
@@ -626,21 +655,16 @@ void ViewportPanel::SaveSettings(const std::string& path) const
for (int i = 0; i < static_cast<int>(m_tiles.size()); ++i) {
ViewportTileSettings s = m_tiles[i]->GetSettings();
f << "\n[Tile" << i << "]\n";
f << "RenderDelegate=" << s.renderDelegate << "\n";
f << "ShowGrid=" << (s.showGrid ? 1 : 0) << "\n";
f << "AAEnabled=" << (s.aaEnabled ? 1 : 0) << "\n";
f << "BgColorR=" << s.bgColorR << "\n";
f << "BgColorG=" << s.bgColorG << "\n";
f << "BgColorB=" << s.bgColorB << "\n";
f << "BBoxMode=" << s.bboxMode << "\n";
f << "AmbientLightOnly=" << (s.ambientLightOnly ? 1 : 0) << "\n";
f << "DomeLightEnabled=" << (s.domeLightEnabled ? 1 : 0) << "\n";
f << "ShadingMode=" << s.shadingMode << "\n";
f << "ColorCorrectionMode=" << s.colorCorrectionMode << "\n";
f << "OcioDisplay=" << s.ocioDisplay << "\n";
f << "OcioView=" << s.ocioView << "\n";
f << "OcioColorSpace=" << s.ocioColorSpace << "\n";
f << "OcioLook=" << s.ocioLook << "\n";
f << "RenderDelegate=" << s.renderDelegate << "\n";
f << "ShowGrid=" << (s.showGrid ? 1 : 0) << "\n";
f << "AAEnabled=" << (s.aaEnabled ? 1 : 0) << "\n";
f << "BgColorR=" << s.bgColorR << "\n";
f << "BgColorG=" << s.bgColorG << "\n";
f << "BgColorB=" << s.bgColorB << "\n";
f << "BBoxMode=" << s.bboxMode << "\n";
f << "AmbientLightOnly=" << (s.ambientLightOnly ? 1 : 0) << "\n";
f << "DomeLightEnabled=" << (s.domeLightEnabled ? 1 : 0) << "\n";
f << "ShadingMode=" << s.shadingMode << "\n";
}
}
@@ -697,7 +721,7 @@ void ViewportPanel::LoadSettings(const std::string& path)
else if (key == "SplitV") splitV = toFloat(val, splitV);
} else {
auto& ts = tileSettings[section];
if (key == "RenderDelegate") ts.renderDelegate = val;
if (key == "RenderDelegate") ts.renderDelegate = val;
else if (key == "ShowGrid") ts.showGrid = (val == "1");
else if (key == "AAEnabled") ts.aaEnabled = (val == "1");
else if (key == "BgColorR") ts.bgColorR = toFloat(val, ts.bgColorR);
@@ -706,12 +730,7 @@ void ViewportPanel::LoadSettings(const std::string& path)
else if (key == "BBoxMode") ts.bboxMode = toInt(val, ts.bboxMode);
else if (key == "AmbientLightOnly") ts.ambientLightOnly = (val == "1");
else if (key == "DomeLightEnabled") ts.domeLightEnabled = (val == "1");
else if (key == "ShadingMode") ts.shadingMode = toInt(val, ts.shadingMode);
else if (key == "ColorCorrectionMode") ts.colorCorrectionMode = toInt(val, ts.colorCorrectionMode);
else if (key == "OcioDisplay") ts.ocioDisplay = val;
else if (key == "OcioView") ts.ocioView = val;
else if (key == "OcioColorSpace") ts.ocioColorSpace = val;
else if (key == "OcioLook") ts.ocioLook = val;
else if (key == "ShadingMode") ts.shadingMode = toInt(val, ts.shadingMode);
}
}
+11 -2
View File
@@ -52,7 +52,7 @@ public:
// ── Main render (called from Application::RenderUI) ──────────────────────
void Render(bool* p_open = nullptr);
// ── Pick callbacks (wired by Application after construction) ─────────────
// ── Callbacks (wired by Application after construction) ──────────────────
std::function<void(const std::string&)> OnPrimPicked;
std::function<void(const std::vector<std::string>&)> OnPrimsPickedRect;
@@ -65,9 +65,18 @@ public:
LayoutMode GetLayout() const { return m_layout; }
int GetFocusedTileIndex() const { return m_focusedTileIndex; }
// ── Global preferences ────────────────────────────────────────────────────
/// Set render delegate on tiles that have no saved delegate yet (empty token).
/// Called once on startup so the pref default applies to fresh tiles.
void ApplyDefaultDelegate(const std::string& delegate);
/// Apply color correction to every tile (always global).
void ApplyGlobalColorCorrection(int ccMode, const std::string& ocioDisplay,
const std::string& ocioView,
const std::string& ocioColorSpace,
const std::string& ocioLook);
// ── Settings persistence ─────────────────────────────────────────────────
/// Load layout and per-tile render settings from a simple INI file.
/// Safe to call immediately after construction (before any Render call).
void LoadSettings(const std::string& path);
/// Save current layout and per-tile render settings to a simple INI file.
void SaveSettings(const std::string& path) const;
+23 -151
View File
@@ -1,6 +1,5 @@
#include "ViewportTile.h"
#include "../utils/Logger.h"
#include "../utils/OcioConfigParser.h"
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdGeom/xformCommonAPI.h>
@@ -100,12 +99,7 @@ ViewportTileSettings ViewportTile::GetSettings() const
s.bboxMode = static_cast<int>(m_renderer.GetBBoxMode());
s.ambientLightOnly = m_renderer.GetAmbientLightOnly();
s.domeLightEnabled = m_renderer.GetDomeLightEnabled();
s.shadingMode = static_cast<int>(m_renderer.GetShadingMode());
s.colorCorrectionMode = static_cast<int>(m_renderer.GetColorCorrectionMode());
s.ocioDisplay = m_renderer.GetOcioDisplay();
s.ocioView = m_renderer.GetOcioView();
s.ocioColorSpace = m_renderer.GetOcioColorSpace();
s.ocioLook = m_renderer.GetOcioLook();
s.shadingMode = static_cast<int>(m_renderer.GetShadingMode());
return s;
}
@@ -120,12 +114,6 @@ void ViewportTile::ApplySettings(const ViewportTileSettings& s)
m_renderer.SetAmbientLightOnly(s.ambientLightOnly);
m_renderer.SetDomeLightEnabled(s.domeLightEnabled);
m_renderer.SetShadingMode(static_cast<ShadingMode>(s.shadingMode));
m_renderer.SetColorCorrectionMode(static_cast<ColorCorrectionMode>(s.colorCorrectionMode));
m_renderer.SetOcioDisplay(s.ocioDisplay);
m_renderer.SetOcioView(s.ocioView);
m_renderer.SetOcioColorSpace(s.ocioColorSpace);
m_renderer.SetOcioLook(s.ocioLook);
m_ocioFieldsSynced = false; // re-seed OCIO edit buffers from restored values
}
// ---------------------------------------------------------------------------
@@ -912,29 +900,31 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
ImGui::TextDisabled("|");
ImGui::SameLine();
// -- Render delegate -----------------------------------------------------
pxr::TfToken currentId = m_renderer.GetCurrentRendererId();
std::string displayName = currentId.IsEmpty()
? "Rdr"
: UsdSceneRenderer::GetRendererDisplayName(currentId);
if (displayName.size() > 8) displayName = displayName.substr(0, 8);
// -- Render delegate (global) --------------------------------------------
{
pxr::TfToken currentId = m_renderer.GetCurrentRendererId();
std::string displayName = currentId.IsEmpty()
? "Rdr"
: UsdSceneRenderer::GetRendererDisplayName(currentId);
if (displayName.size() > 8) displayName = displayName.substr(0, 8);
std::string rdrBtnId = "##Rdr_" + std::to_string(tileIndex);
ImGui::Button(displayName.c_str(), ImVec2(72.0f, 0.0f));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Render delegate -- click to change");
std::string rdrPopupId = "RdrPopup_" + std::to_string(tileIndex);
ImGui::Button(displayName.c_str(), ImVec2(72.0f, 0.0f));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Render delegate");
ImGuiPopupFlags popupFlags = ImGuiPopupFlags_MouseButtonLeft;
std::string rdrPopupId = "RdrPopup_" + std::to_string(tileIndex);
if (ImGui::BeginPopupContextItem(rdrPopupId.c_str(), popupFlags)) {
for (const auto& pluginId : UsdSceneRenderer::GetRendererPlugins()) {
std::string name = UsdSceneRenderer::GetRendererDisplayName(pluginId);
if (name.empty()) name = pluginId.GetString();
bool selected = (pluginId == currentId);
if (ImGui::MenuItem(name.c_str(), nullptr, selected))
if (!selected) m_renderer.SetRendererPlugin(pluginId);
if (ImGui::BeginPopupContextItem(rdrPopupId.c_str(),
ImGuiPopupFlags_MouseButtonLeft))
{
for (const auto& pluginId : UsdSceneRenderer::GetRendererPlugins()) {
std::string name = UsdSceneRenderer::GetRendererDisplayName(pluginId);
if (name.empty()) name = pluginId.GetString();
bool selected = (pluginId == currentId);
if (ImGui::MenuItem(name.c_str(), nullptr, selected) && !selected)
m_renderer.SetRendererPlugin(pluginId);
}
ImGui::EndPopup();
}
ImGui::EndPopup();
}
ImGui::SameLine();
@@ -997,124 +987,6 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
if (ImGui::BeginPopupContextItem(gearPopupId.c_str(),
ImGuiPopupFlags_MouseButtonLeft))
{
// -- Color correction --------------------------------------------
if (ImGui::BeginMenu("Color Correction")) {
ColorCorrectionMode ccm = m_renderer.GetColorCorrectionMode();
auto ccItem = [&](const char* label, ColorCorrectionMode mode) {
if (ImGui::MenuItem(label, nullptr, ccm == mode)) {
m_renderer.SetColorCorrectionMode(mode);
m_ocioFieldsSynced = false;
}
};
ccItem("Disabled", ColorCorrectionMode::Disabled);
ccItem("sRGB", ColorCorrectionMode::sRGB);
ccItem("OpenColorIO", ColorCorrectionMode::OpenColorIO);
if (ccm == ColorCorrectionMode::OpenColorIO) {
ImGui::Separator();
const OcioConfig& ocfg = GetCurrentOcioConfig();
// Seed buffers from renderer, falling back to OCIO config defaults
if (!m_ocioFieldsSynced) {
std::string disp = m_renderer.GetOcioDisplay();
std::string view = m_renderer.GetOcioView();
if (disp.empty()) disp = ocfg.defaultDisplay;
if (view.empty()) view = ocfg.defaultView;
strncpy(m_ocioDisplayBuf, disp.c_str(), 127);
strncpy(m_ocioViewBuf, view.c_str(), 127);
strncpy(m_ocioColorSpaceBuf, m_renderer.GetOcioColorSpace().c_str(), 127);
strncpy(m_ocioLookBuf, m_renderer.GetOcioLook().c_str(), 127);
if (m_renderer.GetOcioDisplay().empty() && !disp.empty())
m_renderer.SetOcioDisplay(disp);
if (m_renderer.GetOcioView().empty() && !view.empty())
m_renderer.SetOcioView(view);
m_ocioFieldsSynced = true;
}
ImGui::PushItemWidth(200.f);
// Display combo
if (ImGui::BeginCombo("Display##ocio", m_ocioDisplayBuf)) {
for (const auto& d : ocfg.displays) {
bool sel = (d == m_ocioDisplayBuf);
if (ImGui::Selectable(d.c_str(), sel)) {
strncpy(m_ocioDisplayBuf, d.c_str(), 127);
m_renderer.SetOcioDisplay(d);
// Auto-select default view for new display
auto vit = ocfg.views.find(d);
if (vit != ocfg.views.end() && !vit->second.empty()) {
strncpy(m_ocioViewBuf, vit->second[0].c_str(), 127);
m_renderer.SetOcioView(vit->second[0]);
}
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// View combo — filtered by current display
{
static const std::vector<std::string> kEmpty;
auto vit = ocfg.views.find(std::string(m_ocioDisplayBuf));
const auto& views = (vit != ocfg.views.end()) ? vit->second : kEmpty;
if (ImGui::BeginCombo("View##ocio", m_ocioViewBuf)) {
for (const auto& v : views) {
bool sel = (v == m_ocioViewBuf);
if (ImGui::Selectable(v.c_str(), sel)) {
strncpy(m_ocioViewBuf, v.c_str(), 127);
m_renderer.SetOcioView(v);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
// Color Space combo
if (ImGui::BeginCombo("Color Space##ocio",
m_ocioColorSpaceBuf[0] ? m_ocioColorSpaceBuf : "(default)")) {
if (ImGui::Selectable("(default)", m_ocioColorSpaceBuf[0] == '\0')) {
m_ocioColorSpaceBuf[0] = '\0';
m_renderer.SetOcioColorSpace("");
}
if (m_ocioColorSpaceBuf[0] == '\0') ImGui::SetItemDefaultFocus();
for (const auto& cs : ocfg.colorSpaces) {
bool sel = (cs == m_ocioColorSpaceBuf);
if (ImGui::Selectable(cs.c_str(), sel)) {
strncpy(m_ocioColorSpaceBuf, cs.c_str(), 127);
m_renderer.SetOcioColorSpace(cs);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// Look combo
if (ImGui::BeginCombo("Look##ocio",
m_ocioLookBuf[0] ? m_ocioLookBuf : "(none)")) {
if (ImGui::Selectable("(none)", m_ocioLookBuf[0] == '\0')) {
m_ocioLookBuf[0] = '\0';
m_renderer.SetOcioLook("");
}
if (m_ocioLookBuf[0] == '\0') ImGui::SetItemDefaultFocus();
for (const auto& look : ocfg.looks) {
bool sel = (look == m_ocioLookBuf);
if (ImGui::Selectable(look.c_str(), sel)) {
strncpy(m_ocioLookBuf, look.c_str(), 127);
m_renderer.SetOcioLook(look);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
}
ImGui::EndMenu();
}
ImGui::Separator();
// -- Shading mode ------------------------------------------------
if (ImGui::BeginMenu("Shading")) {
ShadingMode cur = m_renderer.GetShadingMode();
+5 -16
View File
@@ -17,23 +17,19 @@
namespace UsdLayerManager {
/// Serialisable snapshot of all per-tile render settings.
/// Serialisable snapshot of per-tile render settings.
/// Color correction is global (AppPreferences); render delegate is per-tile.
struct ViewportTileSettings {
std::string renderDelegate; ///< TfToken string, empty = default (Storm)
std::string renderDelegate; ///< empty = use AppPreferences default on first load
bool showGrid = true;
bool aaEnabled = false;
float bgColorR = 0.15f;
float bgColorG = 0.15f;
float bgColorB = 0.15f;
int bboxMode = 0; ///< BBoxMode cast to int
int bboxMode = 0;
bool ambientLightOnly = true;
bool domeLightEnabled = false;
int shadingMode = 0; ///< ShadingMode cast to int (0 = SmoothShaded)
int colorCorrectionMode = 1; ///< ColorCorrectionMode cast to int (1 = sRGB)
std::string ocioDisplay;
std::string ocioView;
std::string ocioColorSpace;
std::string ocioLook;
int shadingMode = 0;
};
/// Named orthographic view directions.
@@ -183,13 +179,6 @@ private:
// ── Orthographic view ────────────────────────────────────────────────────
OrthoView m_orthoView = OrthoView::None;
// ── OCIO InputText edit buffers (per-tile, seeded on mode activation) ────
char m_ocioDisplayBuf[128] = {};
char m_ocioViewBuf[128] = {};
char m_ocioColorSpaceBuf[128] = {};
char m_ocioLookBuf[128] = {};
bool m_ocioFieldsSynced = false;
// ── Per-frame interaction flags ──────────────────────────────────────────
bool m_wasClickedThisFrame = false;
bool m_wasHoveredThisFrame = false;