From 6387bf2d2e16ef93ab8ce3cd9c5d345bab180dab Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 12 Aug 2021 09:04:45 +1000 Subject: [PATCH] [client] rework the configuration overlay to allow for tabs --- client/include/app.h | 5 +- client/renderers/EGL/desktop.c | 9 +- client/renderers/EGL/egl.c | 4 +- client/renderers/EGL/filter_ffx_cas.c | 2 +- client/renderers/EGL/filter_ffx_fsr1.c | 2 +- client/renderers/EGL/postprocess.c | 38 +++++-- client/renderers/EGL/postprocess.h | 5 +- client/src/app.c | 8 +- client/src/overlay/config.c | 146 +++++++++++++++++-------- client/src/overlay/graphs.c | 2 +- client/src/overlays.h | 7 +- 11 files changed, 159 insertions(+), 69 deletions(-) diff --git a/client/include/app.h b/client/include/app.h index f994339f..b849391b 100644 --- a/client/include/app.h +++ b/client/include/app.h @@ -105,7 +105,10 @@ GraphHandle app_registerGraph(const char * name, RingBuffer buffer, float min, f void app_unregisterGraph(GraphHandle handle); void app_overlayConfigRegister(const char * title, - void (*callback)(void * udata), void * udata); + void (*callback)(void * udata, int * id), void * udata); + +void app_overlayConfigRegisterTab(const char * title, + void (*callback)(void * udata, int * id), void * udata); void app_clipboardRelease(void); void app_clipboardNotifyTypes(const LG_ClipboardData types[], int count); diff --git a/client/renderers/EGL/desktop.c b/client/renderers/EGL/desktop.c index 32519ef2..0874fa11 100644 --- a/client/renderers/EGL/desktop.c +++ b/client/renderers/EGL/desktop.c @@ -251,12 +251,6 @@ void egl_desktopConfigUI(EGL_Desktop * desktop) } igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0); igPopItemWidth(); - - if (egl_postProcessImgui(desktop->pp)) - { - atomic_store(&desktop->processFrame, true); - app_invalidateWindow(false); - } } bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format) @@ -366,7 +360,8 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth, int scaleAlgo = EGL_SCALE_NEAREST; - if (atomic_exchange(&desktop->processFrame, false)) + if (atomic_exchange(&desktop->processFrame, false) || + egl_postProcessConfigModified(desktop->pp)) egl_postProcessRun(desktop->pp, desktop->texture, outputWidth, outputHeight); unsigned int finalSizeX, finalSizeY; diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 38ac9928..4ed7b7ba 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -626,7 +626,7 @@ static void debugCallback(GLenum source, GLenum type, GLuint id, DEBUG_PRINT(level, "GL message (source: %s, type: %s): %s", sourceName, typeName, message); } -static void egl_config_ui(void * opaque) +static void egl_configUI(void * opaque, int * id) { struct Inst * this = opaque; egl_damageConfigUI(this->damage); @@ -822,7 +822,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA) return false; } - app_overlayConfigRegister("EGL", egl_config_ui, this); + app_overlayConfigRegister("EGL", egl_configUI, this); this->imgui = true; return true; diff --git a/client/renderers/EGL/filter_ffx_cas.c b/client/renderers/EGL/filter_ffx_cas.c index af867a2d..3b4ebb64 100644 --- a/client/renderers/EGL/filter_ffx_cas.c +++ b/client/renderers/EGL/filter_ffx_cas.c @@ -164,7 +164,7 @@ static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter) bool cas = this->enable; float casSharpness = this->sharpness; - igCheckbox("AMD FidelityFX CAS", &cas); + igCheckbox("Enabled", &cas); if (cas != this->enable) { this->enable = cas; diff --git a/client/renderers/EGL/filter_ffx_fsr1.c b/client/renderers/EGL/filter_ffx_fsr1.c index 3234d137..4e97da29 100644 --- a/client/renderers/EGL/filter_ffx_fsr1.c +++ b/client/renderers/EGL/filter_ffx_fsr1.c @@ -203,7 +203,7 @@ static bool egl_filterFFXFSR1ImguiConfig(EGL_Filter * filter) bool enable = this->enable; float sharpness = this->sharpness; - igCheckbox("AMD FidelityFX FSR", &enable); + igCheckbox("Enabled", &enable); if (enable != this->enable) { this->enable = enable; diff --git a/client/renderers/EGL/postprocess.c b/client/renderers/EGL/postprocess.c index af81b1c6..76f6c9d6 100644 --- a/client/renderers/EGL/postprocess.c +++ b/client/renderers/EGL/postprocess.c @@ -20,6 +20,10 @@ #include "postprocess.h" #include "filters.h" +#include "app.h" +#include "cimgui.h" + +#include #include "common/debug.h" #include "common/array.h" @@ -37,6 +41,7 @@ struct EGL_PostProcess struct ll * filters; GLuint output; unsigned int outputX, outputY; + _Atomic(bool) modified; EGL_Model * model; }; @@ -47,6 +52,27 @@ void egl_postProcessEarlyInit(void) EGL_Filters[i]->earlyInit(); } +static void configUI(void * opaque, int * id) +{ + struct EGL_PostProcess * this = opaque; + + bool redraw = false; + EGL_Filter * filter; + for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); ) + { + igPushIDInt(++*id); + if (igCollapsingHeaderBoolPtr(filter->ops.name, NULL, 0)) + redraw |= egl_filterImguiConfig(filter); + igPopID(); + } + + if (redraw) + { + atomic_store(&this->modified, true); + app_invalidateWindow(false); + } +} + bool egl_postProcessInit(EGL_PostProcess ** pp) { EGL_PostProcess * this = calloc(1, sizeof(*this)); @@ -70,6 +96,8 @@ bool egl_postProcessInit(EGL_PostProcess ** pp) } egl_modelSetDefault(this->model, false); + app_overlayConfigRegisterTab("EGL Filters", configUI, this); + *pp = this; return true; @@ -111,14 +139,9 @@ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops) return true; } -bool egl_postProcessImgui(EGL_PostProcess * this) +bool egl_postProcessConfigModified(EGL_PostProcess * this) { - bool redraw = false; - EGL_Filter * filter; - for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); ) - redraw |= egl_filterImguiConfig(filter); - - return redraw; + return atomic_load(&this->modified); } bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, @@ -131,6 +154,7 @@ bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK) return false; + atomic_store(&this->modified, false); for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); ) { egl_filterSetOutputResHint(filter, targetX, targetY); diff --git a/client/renderers/EGL/postprocess.h b/client/renderers/EGL/postprocess.h index bdf1ccd5..16552721 100644 --- a/client/renderers/EGL/postprocess.h +++ b/client/renderers/EGL/postprocess.h @@ -33,9 +33,8 @@ void egl_postProcessFree(EGL_PostProcess ** pp); /* create and add a filter to this processor */ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops); -/* render the imgui options - * returns true if the filter needs to be re-run */ -bool egl_postProcessImgui(EGL_PostProcess * this); +/* returns true if the configuration was modified since the last run */ +bool egl_postProcessConfigModified(EGL_PostProcess * this); /* apply the filters to the supplied texture * targetX/Y is the final target output dimension hint if scalers are present */ diff --git a/client/src/app.c b/client/src/app.c index c540252e..e50894c5 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -883,7 +883,13 @@ void app_setOverlay(bool enable) } void app_overlayConfigRegister(const char * title, - void (*callback)(void * udata), void * udata) + void (*callback)(void * udata, int * id), void * udata) { overlayConfig_register(title, callback, udata); } + +void app_overlayConfigRegisterTab(const char * title, + void (*callback)(void * udata, int * id), void * udata) +{ + overlayConfig_registerTab(title, callback, udata); +} diff --git a/client/src/overlay/config.c b/client/src/overlay/config.c index aa4b94c1..6a8120ae 100644 --- a/client/src/overlay/config.c +++ b/client/src/overlay/config.c @@ -34,13 +34,14 @@ typedef struct ConfigCallback { const char * title; void * udata; - void (*callback)(void * udata); + void (*callback)(void * udata, int * id); } ConfigCallback; typedef struct OverlayConfig { struct ll * callbacks; + struct ll * tabCallbacks; } OverlayConfig; @@ -48,7 +49,8 @@ static OverlayConfig cfg = { 0 }; static bool config_init(void ** udata, const void * params) { - cfg.callbacks = ll_new(); + cfg.callbacks = ll_new(); + cfg.tabCallbacks = ll_new(); if (!cfg.callbacks) { DEBUG_ERROR("failed to allocate ram"); @@ -58,47 +60,26 @@ static bool config_init(void ** udata, const void * params) return true; } -static void config_free(void * udata) +static void config_freeList(struct ll * list) { ConfigCallback * cb; - while(ll_shift(cfg.callbacks, (void **)&cb)) + while(ll_shift(list, (void **)&cb)) free(cb); - - ll_free(cfg.callbacks); + ll_free(list); } -static int config_render(void * udata, bool interactive, struct Rect * windowRects, - int maxRects) +static void config_free(void * udata) { - if (!interactive) - return 0; + config_freeList(cfg.callbacks); + config_freeList(cfg.tabCallbacks); +} +static void config_renderLGTab(void) +{ const float fontSize = igGetFontSize(); - const ImGuiViewport * viewport = igGetMainViewport(); - igSetNextWindowPos( - (ImVec2){ - viewport->WorkPos.x + 100, - viewport->WorkPos.y + 30 - }, - ImGuiCond_FirstUseEver, - (ImVec2){} - ); - igSetNextWindowSize( - (ImVec2){550, 680}, - ImGuiCond_FirstUseEver); - - if (!igBegin("Configuration", NULL, ImGuiWindowFlags_MenuBar)) - { - overlayGetImGuiRect(windowRects); - igEnd(); - return 1; - } - - igBeginMenuBar(); - igEndMenuBar(); - - if (igCollapsingHeaderBoolPtr("About Looking Glass", NULL, 0)) + if (igCollapsingHeaderBoolPtr("About", NULL, + ImGuiTreeNodeFlags_DefaultOpen)) { igText(LG_COPYRIGHT_STR); overlayTextURL(LG_WEBSITE_STR, NULL); @@ -107,7 +88,8 @@ static int config_render(void * udata, bool interactive, struct Rect * windowRec igTextWrapped(LG_LICENSE_STR); } - if (igCollapsingHeaderBoolPtr("Help & Support", NULL, 0)) + if (igCollapsingHeaderBoolPtr("Help & Support", NULL, + ImGuiTreeNodeFlags_DefaultOpen)) { igBeginTable("split", 2, 0, (ImVec2){}, 0.0f); igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, fontSize * 9.0f, 0); @@ -121,7 +103,8 @@ static int config_render(void * udata, bool interactive, struct Rect * windowRec igEndTable(); } - if (igCollapsingHeaderBoolPtr("The Looking Glass Team / Donations", NULL, 0)) + if (igCollapsingHeaderBoolPtr("The Looking Glass Team / Donations", NULL, + ImGuiTreeNodeFlags_DefaultOpen)) { for(const struct LGTeamMember * member = LG_TEAM; member->name; ++member) { @@ -154,17 +137,82 @@ static int config_render(void * udata, bool interactive, struct Rect * windowRec } } } +} + +static int config_render(void * udata, bool interactive, struct Rect * windowRects, + int maxRects) +{ + if (!interactive) + return 0; + + int id = 1000; + + const ImGuiViewport * viewport = igGetMainViewport(); + igSetNextWindowPos( + (ImVec2){ + viewport->WorkPos.x + 100, + viewport->WorkPos.y + 30 + }, + ImGuiCond_FirstUseEver, + (ImVec2){} + ); + + igSetNextWindowSize( + (ImVec2){550, 680}, + ImGuiCond_FirstUseEver); + + igPushIDInt(id++); + if (!igBegin("Configuration", NULL, ImGuiWindowFlags_MenuBar)) + { + overlayGetImGuiRect(windowRects); + igEnd(); + igPopID(); + return 1; + } + + igBeginMenuBar(); + igEndMenuBar(); + + igBeginTabBar("Configuration#tabs", 0); + + if (igBeginTabItem("Looking Glass", NULL, 0)) + { + config_renderLGTab(); + igEndTabItem(); + } ConfigCallback * cb; - for (ll_reset(cfg.callbacks); ll_walk(cfg.callbacks, (void **)&cb); ) + + if (igBeginTabItem("Settings", NULL, 0)) { - if (!igCollapsingHeaderBoolPtr(cb->title, NULL, 0)) - continue; - cb->callback(cb->udata); + for (ll_reset(cfg.callbacks); ll_walk(cfg.callbacks, (void **)&cb); ) + { + if (!igCollapsingHeaderBoolPtr(cb->title, NULL, 0)) + continue; + + igPushIDInt(id++); + cb->callback(cb->udata, &id); + igPopID(); + } + igEndTabItem(); } + for (ll_reset(cfg.tabCallbacks); ll_walk(cfg.tabCallbacks, (void **)&cb); ) + { + if (!igBeginTabItem(cb->title, NULL, 0)) + continue; + + igPushIDInt(id++); + cb->callback(cb->udata, &id); + igPopID(); + igEndTabItem(); + } + + igEndTabBar(); + overlayGetImGuiRect(windowRects); igEnd(); + igPopID(); return 1; } @@ -176,8 +224,8 @@ struct LG_OverlayOps LGOverlayConfig = .render = config_render }; -void overlayConfig_register(const char * title, void (*callback)(void * udata), - void * udata) +static void config_addToList(struct ll * list, const char * title, + void(*callback)(void * udata, int * id), void * udata) { ConfigCallback * cb = calloc(1, sizeof(*cb)); if (!cb) @@ -189,5 +237,17 @@ void overlayConfig_register(const char * title, void (*callback)(void * udata), cb->title = title; cb->udata = udata; cb->callback = callback; - ll_push(cfg.callbacks, cb); + ll_push(list, cb); +} + +void overlayConfig_register(const char * title, + void (*callback)(void * udata, int * id), void * udata) +{ + config_addToList(cfg.callbacks, title, callback, udata); +}; + +void overlayConfig_registerTab(const char * title, + void (*callback)(void * udata, int * id), void * udata) +{ + config_addToList(cfg.tabCallbacks, title, callback, udata); }; diff --git a/client/src/overlay/graphs.c b/client/src/overlay/graphs.c index df6ead23..bef9bfc1 100644 --- a/client/src/overlay/graphs.c +++ b/client/src/overlay/graphs.c @@ -45,7 +45,7 @@ struct OverlayGraph }; -static void configCallback(void * udata) +static void configCallback(void * udata, int * id) { igCheckbox("Show Timing Graphs", &gs.show); igSeparator(); diff --git a/client/src/overlays.h b/client/src/overlays.h index 696fb10f..9b2f8e93 100644 --- a/client/src/overlays.h +++ b/client/src/overlays.h @@ -35,7 +35,10 @@ void overlayGraph_unregister(); void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name, bool * enabled, void * udata), void * udata); -void overlayConfig_register(const char * title, void (*callback)(void * udata), - void * udata); +void overlayConfig_register(const char * title, + void (*callback)(void * udata, int * id), void * udata); + +void overlayConfig_registerTab(const char * title, + void (*callback)(void * udata, int * id), void * udata); #endif