Skip to content

Commit

Permalink
Remove the need to define the imgui function table in add-on projects
Browse files Browse the repository at this point in the history
  • Loading branch information
crosire committed Oct 24, 2021
1 parent 7ad2f33 commit 56339ff
Show file tree
Hide file tree
Showing 12 changed files with 436 additions and 437 deletions.
10 changes: 3 additions & 7 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,15 @@ For more complex examples, see the [examples directory in this repository](../ex
## Overlays
It is also supported to add an overlay, which can e.g. be used to display debug information or interact with the user in-application.
Overlays are created with the use of [Dear ImGui](https://github.com/ocornut/imgui/). Including the `reshade.hpp` header after `imgui.h` will automatically overwrite all Dear ImGui functions to use the instance created and managed by ReShade. This means all you have to do is include these two headers, define the function table variable in one of your source code file and use Dear ImGui as usual (without actually having to build its source code files, only the header files are needed):
Overlays are created with the use of [Dear ImGui](https://github.com/ocornut/imgui/). Including the `reshade.hpp` header after `imgui.h` will automatically overwrite all Dear ImGui functions to use the instance created and managed by ReShade. This means all you have to do is include these two headers and use Dear ImGui as usual (without having to build its source code files):
```cpp
#include <imgui.h>
#include <reshade.hpp>
// Define this variable in exactly one of your source code files.
// The function table is automatically populated in the call to 'reshade::register_addon()' and overwrites all Dear ImGui functions.
imgui_function_table g_imgui_function_table = {};
bool g_popup_window_visible = false;
static void draw_debug_overlay(reshade::api::effect_runtime *runtime, void *imgui_context)
static void draw_debug_overlay(reshade::api::effect_runtime *runtime)
{
ImGui::TextUnformatted("Some text");
Expand All @@ -72,7 +68,7 @@ static void draw_debug_overlay(reshade::api::effect_runtime *runtime, void *imgu
}
}
static void draw_settings_overlay(reshade::api::effect_runtime *runtime, void *imgui_context)
static void draw_settings_overlay(reshade::api::effect_runtime *runtime)
{
ImGui::Checkbox("Popup window is visible", &g_popup_window_visible);
}
Expand Down
4 changes: 1 addition & 3 deletions examples/api_trace/api_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <unordered_map>
#include <cassert>

imgui_function_table g_imgui_function_table;

namespace
{
bool s_do_capture = false;
Expand Down Expand Up @@ -789,7 +787,7 @@ static void on_present(reshade::api::command_queue *, reshade::api::swapchain *)
s_do_capture = false;
}

static void draw_overlay(reshade::api::effect_runtime *, void *)
static void draw_overlay(reshade::api::effect_runtime *)
{
if (!s_do_capture)
{
Expand Down
4 changes: 1 addition & 3 deletions examples/generic_depth/generic_depth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ static std::mutex s_mutex;

#ifdef BUILTIN_ADDON
#include "ini_file.hpp"
#else
imgui_function_table g_imgui_function_table;
#endif

using namespace reshade::api;
Expand Down Expand Up @@ -692,7 +690,7 @@ static void on_finish_render_effects(effect_runtime *runtime, command_list *cmd_
}
}

static void draw_settings_overlay(effect_runtime *runtime, void *)
static void draw_settings_overlay(effect_runtime *runtime)
{
device *const device = runtime->get_device();
state_tracking_context &device_state = device->get_private_data<state_tracking_context>(state_tracking_context::GUID);
Expand Down
4 changes: 1 addition & 3 deletions examples/texturemod_dump/texturemod_overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <unordered_set>
#include <malloc.h>

imgui_function_table g_imgui_function_table;

using namespace reshade::api;

struct set_data
Expand Down Expand Up @@ -313,7 +311,7 @@ static void on_present(command_queue *queue, swapchain *runtime)
// See implementation in 'texturemod_dump.cpp'
extern bool dump_texture(command_queue *queue, resource tex, const resource_desc &desc);

static void draw_overlay(effect_runtime *runtime, void *)
static void draw_overlay(effect_runtime *runtime)
{
assert(s_is_in_reshade_runtime);

Expand Down
117 changes: 62 additions & 55 deletions include/reshade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,62 @@
#include <Psapi.h>

#define RESHADE_API_VERSION 1
#define RESHADE_API_VERSION_IMGUI IMGUI_VERSION_NUM

namespace reshade
{
/// <summary>
/// Gets the handle to the ReShade module in the current process.
/// </summary>
inline HMODULE &get_reshade_module_handle()
namespace internal
{
static HMODULE handle = nullptr;
if (handle == nullptr)
/// <summary>
/// Gets the handle to the ReShade module in the current process.
/// </summary>
inline HMODULE &get_reshade_module_handle()
{
// Use the kernel32 variant of module enumeration functions so it can be safely called from 'DllMain'
HMODULE modules[1024]; DWORD num = 0;
if (K32EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &num))
static HMODULE handle = nullptr;
if (handle == nullptr)
{
if (num > sizeof(modules))
num = sizeof(modules);

for (DWORD i = 0; i < num / sizeof(HMODULE); ++i)
// Use the kernel32 variant of module enumeration functions so it can be safely called from 'DllMain'
HMODULE modules[1024]; DWORD num = 0;
if (K32EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &num))
{
if (GetProcAddress(modules[i], "ReShadeRegisterAddon") &&
GetProcAddress(modules[i], "ReShadeUnregisterAddon"))
if (num > sizeof(modules))
num = sizeof(modules);

for (DWORD i = 0; i < num / sizeof(HMODULE); ++i)
{
handle = modules[i];
break;
if (GetProcAddress(modules[i], "ReShadeRegisterAddon") &&
GetProcAddress(modules[i], "ReShadeUnregisterAddon"))
{
handle = modules[i];
break;
}
}
}
}
return handle;
}
return handle;
}
/// <summary>
/// Gets the handle to the current add-on module.
/// </summary>
inline HMODULE &get_current_module_handle()
{
static HMODULE handle = nullptr;
return handle;

/// <summary>
/// Gets the handle to the current add-on module.
/// </summary>
inline HMODULE &get_current_module_handle()
{
static HMODULE handle = nullptr;
return handle;
}

#if defined(IMGUI_VERSION_NUM)
/// <summary>
/// Gets a pointer to the Dear ImGui function table.
/// </summary>
inline const imgui_function_table *get_imgui_function_table()
{
static const auto func = reinterpret_cast<const imgui_function_table *(*)(uint32_t)>(
GetProcAddress(get_reshade_module_handle(), "ReShadeGetImGuiFunctionTable"));
if (func != nullptr)
return func(IMGUI_VERSION_NUM);
return nullptr;
}
#endif
}

/// <summary>
Expand All @@ -60,8 +77,8 @@ namespace reshade
inline void log_message(int level, const char *message)
{
static const auto func = reinterpret_cast<void(*)(HMODULE, int, const char *)>(
GetProcAddress(get_reshade_module_handle(), "ReShadeLogMessage"));
func(get_current_module_handle(), level, message);
GetProcAddress(internal::get_reshade_module_handle(), "ReShadeLogMessage"));
func(internal::get_current_module_handle(), level, message);
}

/// <summary>
Expand All @@ -71,9 +88,9 @@ namespace reshade
/// <param name="module">Handle of the current add-on module.</param>
inline bool register_addon(HMODULE module)
{
get_current_module_handle() = module;
internal::get_current_module_handle() = module;

const HMODULE reshade_module = get_reshade_module_handle();
const HMODULE reshade_module = internal::get_reshade_module_handle();
if (reshade_module == nullptr)
return false;

Expand All @@ -83,18 +100,10 @@ namespace reshade
if (!func(module, RESHADE_API_VERSION))
return false;

#if defined(IMGUI_VERSION)
// Check that the ReShade module was built with Dear ImGui support
const auto imgui_func = reinterpret_cast<const imgui_function_table *(*)(uint32_t)>(
GetProcAddress(reshade_module, "ReShadeGetImGuiFunctionTable"));
if (imgui_func == nullptr)
return false;

// Check that the ReShade module supports the used Dear ImGui version
const imgui_function_table *const imgui_table = imgui_func(RESHADE_API_VERSION_IMGUI);
if (imgui_table == nullptr)
#if defined(IMGUI_VERSION_NUM)
// Check that the ReShade module was built with Dear ImGui support and supports the used Dear ImGui version
if (!internal::get_imgui_function_table())
return false;
g_imgui_function_table = *imgui_table;
#endif

return true;
Expand All @@ -105,7 +114,7 @@ namespace reshade
/// <param name="module">Handle of the current add-on module.</param>
inline void unregister_addon(HMODULE module)
{
const HMODULE reshade_module = get_reshade_module_handle();
const HMODULE reshade_module = internal::get_reshade_module_handle();
if (reshade_module == nullptr)
return;

Expand All @@ -123,7 +132,7 @@ namespace reshade
inline void register_event(typename reshade::addon_event_traits<ev>::decl callback)
{
static const auto func = reinterpret_cast<void(*)(reshade::addon_event, void *)>(
GetProcAddress(get_reshade_module_handle(), "ReShadeRegisterEvent"));
GetProcAddress(internal::get_reshade_module_handle(), "ReShadeRegisterEvent"));
func(ev, static_cast<void *>(callback));
}
/// <summary>
Expand All @@ -134,7 +143,7 @@ namespace reshade
inline void unregister_event(typename reshade::addon_event_traits<ev>::decl callback)
{
static const auto func = reinterpret_cast<void(*)(reshade::addon_event, void *)>(
GetProcAddress(get_reshade_module_handle(), "ReShadeUnregisterEvent"));
GetProcAddress(internal::get_reshade_module_handle(), "ReShadeUnregisterEvent"));
func(ev, static_cast<void *>(callback));
}

Expand All @@ -144,23 +153,21 @@ namespace reshade
/// </summary>
/// <param name="title">A null-terminated title string, or <see langword="nullptr"/> to register a settings overlay for this add-on.</param>
/// <param name="callback">Pointer to the callback function.</param>
inline void register_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime, void *imgui_context))
inline void register_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime))
{
static const auto func = reinterpret_cast<void(*)(const char *, void(*)(reshade::api::effect_runtime *, void *))>(
GetProcAddress(get_reshade_module_handle(), "ReShadeRegisterOverlay"));
if (func != nullptr) // May not exist if ReShade was built without "RESHADE_GUI" defined
func(title, callback);
static const auto func = reinterpret_cast<void(*)(const char *, void(*)(reshade::api::effect_runtime *))>(
GetProcAddress(internal::get_reshade_module_handle(), "ReShadeRegisterOverlay"));
func(title, callback);
}
/// <summary>
/// Unregisters an overlay that was previously registered via <see cref="register_overlay"/>.
/// </summary>
/// <param name="title">A null-terminated title string.</param>
/// <param name="callback">Pointer to the callback function.</param>
inline void unregister_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime, void *imgui_context))
inline void unregister_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime))
{
static const auto func = reinterpret_cast<void(*)(const char *, void(*)(reshade::api::effect_runtime *, void *))>(
GetProcAddress(get_reshade_module_handle(), "ReShadeUnregisterOverlay"));
if (func != nullptr)
func(title, callback);
static const auto func = reinterpret_cast<void(*)(const char *, void(*)(reshade::api::effect_runtime *))>(
GetProcAddress(internal::get_reshade_module_handle(), "ReShadeUnregisterOverlay"));
func(title, callback);
}
}
Loading

0 comments on commit 56339ff

Please sign in to comment.