[client] rework the configuration overlay to allow for tabs

This commit is contained in:
Geoffrey McRae 2021-08-12 09:04:45 +10:00
parent fe6339fc77
commit 6387bf2d2e
11 changed files with 159 additions and 69 deletions

View File

@ -105,7 +105,10 @@ GraphHandle app_registerGraph(const char * name, RingBuffer buffer, float min, f
void app_unregisterGraph(GraphHandle handle); void app_unregisterGraph(GraphHandle handle);
void app_overlayConfigRegister(const char * title, 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_clipboardRelease(void);
void app_clipboardNotifyTypes(const LG_ClipboardData types[], int count); void app_clipboardNotifyTypes(const LG_ClipboardData types[], int count);

View File

@ -251,12 +251,6 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
} }
igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0); igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
igPopItemWidth(); igPopItemWidth();
if (egl_postProcessImgui(desktop->pp))
{
atomic_store(&desktop->processFrame, true);
app_invalidateWindow(false);
}
} }
bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format) 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; 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); egl_postProcessRun(desktop->pp, desktop->texture, outputWidth, outputHeight);
unsigned int finalSizeX, finalSizeY; unsigned int finalSizeX, finalSizeY;

View File

@ -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); 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; struct Inst * this = opaque;
egl_damageConfigUI(this->damage); egl_damageConfigUI(this->damage);
@ -822,7 +822,7 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
return false; return false;
} }
app_overlayConfigRegister("EGL", egl_config_ui, this); app_overlayConfigRegister("EGL", egl_configUI, this);
this->imgui = true; this->imgui = true;
return true; return true;

View File

@ -164,7 +164,7 @@ static bool egl_filterFFXCASImguiConfig(EGL_Filter * filter)
bool cas = this->enable; bool cas = this->enable;
float casSharpness = this->sharpness; float casSharpness = this->sharpness;
igCheckbox("AMD FidelityFX CAS", &cas); igCheckbox("Enabled", &cas);
if (cas != this->enable) if (cas != this->enable)
{ {
this->enable = cas; this->enable = cas;

View File

@ -203,7 +203,7 @@ static bool egl_filterFFXFSR1ImguiConfig(EGL_Filter * filter)
bool enable = this->enable; bool enable = this->enable;
float sharpness = this->sharpness; float sharpness = this->sharpness;
igCheckbox("AMD FidelityFX FSR", &enable); igCheckbox("Enabled", &enable);
if (enable != this->enable) if (enable != this->enable)
{ {
this->enable = enable; this->enable = enable;

View File

@ -20,6 +20,10 @@
#include "postprocess.h" #include "postprocess.h"
#include "filters.h" #include "filters.h"
#include "app.h"
#include "cimgui.h"
#include <stdatomic.h>
#include "common/debug.h" #include "common/debug.h"
#include "common/array.h" #include "common/array.h"
@ -37,6 +41,7 @@ struct EGL_PostProcess
struct ll * filters; struct ll * filters;
GLuint output; GLuint output;
unsigned int outputX, outputY; unsigned int outputX, outputY;
_Atomic(bool) modified;
EGL_Model * model; EGL_Model * model;
}; };
@ -47,6 +52,27 @@ void egl_postProcessEarlyInit(void)
EGL_Filters[i]->earlyInit(); 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) bool egl_postProcessInit(EGL_PostProcess ** pp)
{ {
EGL_PostProcess * this = calloc(1, sizeof(*this)); EGL_PostProcess * this = calloc(1, sizeof(*this));
@ -70,6 +96,8 @@ bool egl_postProcessInit(EGL_PostProcess ** pp)
} }
egl_modelSetDefault(this->model, false); egl_modelSetDefault(this->model, false);
app_overlayConfigRegisterTab("EGL Filters", configUI, this);
*pp = this; *pp = this;
return true; return true;
@ -111,14 +139,9 @@ bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops)
return true; return true;
} }
bool egl_postProcessImgui(EGL_PostProcess * this) bool egl_postProcessConfigModified(EGL_PostProcess * this)
{ {
bool redraw = false; return atomic_load(&this->modified);
EGL_Filter * filter;
for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); )
redraw |= egl_filterImguiConfig(filter);
return redraw;
} }
bool egl_postProcessRun(EGL_PostProcess * this, EGL_Texture * tex, 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) if (egl_textureGet(tex, &texture, &sizeX, &sizeY) != EGL_TEX_STATUS_OK)
return false; return false;
atomic_store(&this->modified, false);
for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); ) for(ll_reset(this->filters); ll_walk(this->filters, (void **)&filter); )
{ {
egl_filterSetOutputResHint(filter, targetX, targetY); egl_filterSetOutputResHint(filter, targetX, targetY);

View File

@ -33,9 +33,8 @@ void egl_postProcessFree(EGL_PostProcess ** pp);
/* create and add a filter to this processor */ /* create and add a filter to this processor */
bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops); bool egl_postProcessAdd(EGL_PostProcess * this, const EGL_FilterOps * ops);
/* render the imgui options /* returns true if the configuration was modified since the last run */
* returns true if the filter needs to be re-run */ bool egl_postProcessConfigModified(EGL_PostProcess * this);
bool egl_postProcessImgui(EGL_PostProcess * this);
/* apply the filters to the supplied texture /* apply the filters to the supplied texture
* targetX/Y is the final target output dimension hint if scalers are present */ * targetX/Y is the final target output dimension hint if scalers are present */

View File

@ -883,7 +883,13 @@ void app_setOverlay(bool enable)
} }
void app_overlayConfigRegister(const char * title, 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); overlayConfig_register(title, callback, udata);
} }
void app_overlayConfigRegisterTab(const char * title,
void (*callback)(void * udata, int * id), void * udata)
{
overlayConfig_registerTab(title, callback, udata);
}

View File

@ -34,13 +34,14 @@ typedef struct ConfigCallback
{ {
const char * title; const char * title;
void * udata; void * udata;
void (*callback)(void * udata); void (*callback)(void * udata, int * id);
} }
ConfigCallback; ConfigCallback;
typedef struct OverlayConfig typedef struct OverlayConfig
{ {
struct ll * callbacks; struct ll * callbacks;
struct ll * tabCallbacks;
} }
OverlayConfig; OverlayConfig;
@ -48,7 +49,8 @@ static OverlayConfig cfg = { 0 };
static bool config_init(void ** udata, const void * params) static bool config_init(void ** udata, const void * params)
{ {
cfg.callbacks = ll_new(); cfg.callbacks = ll_new();
cfg.tabCallbacks = ll_new();
if (!cfg.callbacks) if (!cfg.callbacks)
{ {
DEBUG_ERROR("failed to allocate ram"); DEBUG_ERROR("failed to allocate ram");
@ -58,47 +60,26 @@ static bool config_init(void ** udata, const void * params)
return true; return true;
} }
static void config_free(void * udata) static void config_freeList(struct ll * list)
{ {
ConfigCallback * cb; ConfigCallback * cb;
while(ll_shift(cfg.callbacks, (void **)&cb)) while(ll_shift(list, (void **)&cb))
free(cb); free(cb);
ll_free(list);
ll_free(cfg.callbacks);
} }
static int config_render(void * udata, bool interactive, struct Rect * windowRects, static void config_free(void * udata)
int maxRects)
{ {
if (!interactive) config_freeList(cfg.callbacks);
return 0; config_freeList(cfg.tabCallbacks);
}
static void config_renderLGTab(void)
{
const float fontSize = igGetFontSize(); const float fontSize = igGetFontSize();
const ImGuiViewport * viewport = igGetMainViewport();
igSetNextWindowPos(
(ImVec2){
viewport->WorkPos.x + 100,
viewport->WorkPos.y + 30
},
ImGuiCond_FirstUseEver,
(ImVec2){}
);
igSetNextWindowSize( if (igCollapsingHeaderBoolPtr("About", NULL,
(ImVec2){550, 680}, ImGuiTreeNodeFlags_DefaultOpen))
ImGuiCond_FirstUseEver);
if (!igBegin("Configuration", NULL, ImGuiWindowFlags_MenuBar))
{
overlayGetImGuiRect(windowRects);
igEnd();
return 1;
}
igBeginMenuBar();
igEndMenuBar();
if (igCollapsingHeaderBoolPtr("About Looking Glass", NULL, 0))
{ {
igText(LG_COPYRIGHT_STR); igText(LG_COPYRIGHT_STR);
overlayTextURL(LG_WEBSITE_STR, NULL); overlayTextURL(LG_WEBSITE_STR, NULL);
@ -107,7 +88,8 @@ static int config_render(void * udata, bool interactive, struct Rect * windowRec
igTextWrapped(LG_LICENSE_STR); igTextWrapped(LG_LICENSE_STR);
} }
if (igCollapsingHeaderBoolPtr("Help & Support", NULL, 0)) if (igCollapsingHeaderBoolPtr("Help & Support", NULL,
ImGuiTreeNodeFlags_DefaultOpen))
{ {
igBeginTable("split", 2, 0, (ImVec2){}, 0.0f); igBeginTable("split", 2, 0, (ImVec2){}, 0.0f);
igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, fontSize * 9.0f, 0); igTableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, fontSize * 9.0f, 0);
@ -121,7 +103,8 @@ static int config_render(void * udata, bool interactive, struct Rect * windowRec
igEndTable(); 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) 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; ConfigCallback * cb;
for (ll_reset(cfg.callbacks); ll_walk(cfg.callbacks, (void **)&cb); )
if (igBeginTabItem("Settings", NULL, 0))
{ {
if (!igCollapsingHeaderBoolPtr(cb->title, NULL, 0)) for (ll_reset(cfg.callbacks); ll_walk(cfg.callbacks, (void **)&cb); )
continue; {
cb->callback(cb->udata); 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); overlayGetImGuiRect(windowRects);
igEnd(); igEnd();
igPopID();
return 1; return 1;
} }
@ -176,8 +224,8 @@ struct LG_OverlayOps LGOverlayConfig =
.render = config_render .render = config_render
}; };
void overlayConfig_register(const char * title, void (*callback)(void * udata), static void config_addToList(struct ll * list, const char * title,
void * udata) void(*callback)(void * udata, int * id), void * udata)
{ {
ConfigCallback * cb = calloc(1, sizeof(*cb)); ConfigCallback * cb = calloc(1, sizeof(*cb));
if (!cb) if (!cb)
@ -189,5 +237,17 @@ void overlayConfig_register(const char * title, void (*callback)(void * udata),
cb->title = title; cb->title = title;
cb->udata = udata; cb->udata = udata;
cb->callback = callback; 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);
}; };

View File

@ -45,7 +45,7 @@ struct OverlayGraph
}; };
static void configCallback(void * udata) static void configCallback(void * udata, int * id)
{ {
igCheckbox("Show Timing Graphs", &gs.show); igCheckbox("Show Timing Graphs", &gs.show);
igSeparator(); igSeparator();

View File

@ -35,7 +35,10 @@ void overlayGraph_unregister();
void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name, void overlayGraph_iterate(void (*callback)(GraphHandle handle, const char * name,
bool * enabled, void * udata), void * udata); bool * enabled, void * udata), void * udata);
void overlayConfig_register(const char * title, void (*callback)(void * udata), void overlayConfig_register(const char * title,
void * udata); void (*callback)(void * udata, int * id), void * udata);
void overlayConfig_registerTab(const char * title,
void (*callback)(void * udata, int * id), void * udata);
#endif #endif