mirror of
https://github.com/rt64/rt64.git
synced 2025-03-14 13:21:24 +00:00
Add inspector with hooks for SDL2.
This commit is contained in:
parent
1812bc03c3
commit
33fd9fd88d
@ -333,6 +333,7 @@ set (SOURCES
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/imgui_draw.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/imgui_tables.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/imgui_widgets.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/backends/imgui_impl_sdl2.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/imgui/backends/imgui_impl_vulkan.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/im3d/im3d.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/src/contrib/implot/implot.cpp"
|
||||
|
@ -12,6 +12,12 @@
|
||||
#include "imgui/imgui.h"
|
||||
#include "implot/implot.h"
|
||||
|
||||
// Volk must be included before the ImGui Vulkan backend.
|
||||
#include "vulkan/rt64_vulkan.h"
|
||||
|
||||
#include "imgui/backends/imgui_impl_sdl2.h"
|
||||
#include "imgui/backends/imgui_impl_vulkan.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include "imgui/backends/imgui_impl_dx12.h"
|
||||
# include "imgui/backends/imgui_impl_win32.h"
|
||||
@ -22,10 +28,6 @@
|
||||
# include "d3d12/rt64_d3d12.h"
|
||||
#endif
|
||||
|
||||
// Volk must be included before the ImGui Vulkan backend.
|
||||
#include "vulkan/rt64_vulkan.h"
|
||||
#include "imgui/backends/imgui_impl_vulkan.h"
|
||||
|
||||
static std::string IniFilenameUTF8;
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -240,4 +242,18 @@ namespace RT64 {
|
||||
return ImGui_ImplWin32_WndProcHandler(swapChain->getWindow(), msg, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Inspector::handleSdlEvent(SDL_Event *event) {
|
||||
bool processed = ImGui_ImplSDL2_ProcessEvent(event);
|
||||
if (processed) {
|
||||
if ((event->type == SDL_KEYDOWN) || (event->type == SDL_KEYUP)) {
|
||||
return ImGui::GetIO().WantCaptureKeyboard;
|
||||
}
|
||||
else if ((event->type == SDL_MOUSEMOTION) || (event->type == SDL_MOUSEBUTTONDOWN) || (event->type == SDL_MOUSEBUTTONUP) || (event->type == SDL_MOUSEWHEEL)) {
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
@ -14,6 +14,7 @@
|
||||
#include "common/rt64_common.h"
|
||||
#include "common/rt64_user_configuration.h"
|
||||
#include "render/rt64_render_worker.h"
|
||||
#include "hle/rt64_application_window.h"
|
||||
#include "rhi/rt64_render_interface.h"
|
||||
|
||||
namespace RT64 {
|
||||
@ -36,5 +37,6 @@ namespace RT64 {
|
||||
# ifdef _WIN32
|
||||
bool handleMessage(UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
# endif
|
||||
bool handleSdlEvent(SDL_Event *event);
|
||||
};
|
||||
};
|
@ -390,6 +390,7 @@ namespace RT64 {
|
||||
}
|
||||
|
||||
void Application::updateScreen() {
|
||||
appWindow->sdlCheckFilterInstallation();
|
||||
screenApiProfiler.logAndRestart();
|
||||
state->updateScreen(core.decodeVI(), false);
|
||||
}
|
||||
@ -448,43 +449,20 @@ namespace RT64 {
|
||||
switch (message) {
|
||||
case WM_KEYDOWN: {
|
||||
switch (wParam) {
|
||||
case VK_F1: {
|
||||
if (userConfig.developerMode) {
|
||||
const std::lock_guard<std::mutex> lock(presentQueue->inspectorMutex);
|
||||
if (presentQueue->inspector == nullptr) {
|
||||
presentQueue->inspector = std::make_unique<Inspector>(device.get(), swapChain.get(), createdGraphicsAPI);
|
||||
if (!userPaths.isEmpty()) {
|
||||
presentQueue->inspector->setIniPath(userPaths.imguiPath);
|
||||
}
|
||||
|
||||
freeCamClearQueued = true;
|
||||
appWindow->blockSdlKeyboard();
|
||||
}
|
||||
else if (presentQueue->inspector != nullptr) {
|
||||
presentQueue->inspector.reset(nullptr);
|
||||
appWindow->unblockSdlKeyboard();
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "Inspector is not available: developer mode is not enabled in the configuration.\n");
|
||||
}
|
||||
|
||||
case VK_F1:
|
||||
processDeveloperShortcut(DeveloperShortcut::Inspector);
|
||||
return true;
|
||||
}
|
||||
case VK_F2: {
|
||||
workloadQueue->rtEnabled = !workloadQueue->rtEnabled;
|
||||
case VK_F2:
|
||||
processDeveloperShortcut(DeveloperShortcut::RayTracing);
|
||||
return true;
|
||||
}
|
||||
case VK_F3: {
|
||||
presentQueue->viewRDRAM = !presentQueue->viewRDRAM;
|
||||
case VK_F3:
|
||||
processDeveloperShortcut(DeveloperShortcut::ViewRDRAM);
|
||||
return true;
|
||||
}
|
||||
case VK_F4: {
|
||||
textureCache->textureMap.replacementMapEnabled = !textureCache->textureMap.replacementMapEnabled;
|
||||
case VK_F4:
|
||||
processDeveloperShortcut(DeveloperShortcut::Replacements);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
// Ignore key.
|
||||
// Unknown shortcut.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -492,11 +470,79 @@ namespace RT64 {
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Application::sdlEventFilter(SDL_Event *event) {
|
||||
if (userConfig.developerMode && (presentQueue != nullptr) && (state != nullptr) && !FileDialog::isOpen) {
|
||||
const std::lock_guard<std::mutex> lock(presentQueue->inspectorMutex);
|
||||
if ((presentQueue->inspector != nullptr) && presentQueue->inspector->handleSdlEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type == SDL_KEYDOWN) {
|
||||
switch (event->key.keysym.scancode) {
|
||||
case SDL_SCANCODE_F1:
|
||||
processDeveloperShortcut(DeveloperShortcut::Inspector);
|
||||
return true;
|
||||
case SDL_SCANCODE_F2:
|
||||
processDeveloperShortcut(DeveloperShortcut::RayTracing);
|
||||
return true;
|
||||
case SDL_SCANCODE_F3:
|
||||
processDeveloperShortcut(DeveloperShortcut::ViewRDRAM);
|
||||
return true;
|
||||
case SDL_SCANCODE_F4:
|
||||
processDeveloperShortcut(DeveloperShortcut::Replacements);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Application::usesWindowMessageFilter() {
|
||||
return userConfig.developerMode;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::processDeveloperShortcut(DeveloperShortcut developerShortcut) {
|
||||
switch (developerShortcut) {
|
||||
case DeveloperShortcut::Inspector: {
|
||||
if (userConfig.developerMode) {
|
||||
const std::lock_guard<std::mutex> lock(presentQueue->inspectorMutex);
|
||||
if (presentQueue->inspector == nullptr) {
|
||||
presentQueue->inspector = std::make_unique<Inspector>(device.get(), swapChain.get(), createdGraphicsAPI);
|
||||
if (!userPaths.isEmpty()) {
|
||||
presentQueue->inspector->setIniPath(userPaths.imguiPath);
|
||||
}
|
||||
|
||||
freeCamClearQueued = true;
|
||||
}
|
||||
else if (presentQueue->inspector != nullptr) {
|
||||
presentQueue->inspector.reset(nullptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "Inspector is not available: developer mode is not enabled in the configuration.\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case DeveloperShortcut::RayTracing: {
|
||||
workloadQueue->rtEnabled = !workloadQueue->rtEnabled;
|
||||
break;
|
||||
}
|
||||
case DeveloperShortcut::ViewRDRAM: {
|
||||
presentQueue->viewRDRAM = !presentQueue->viewRDRAM;
|
||||
break;
|
||||
}
|
||||
case DeveloperShortcut::Replacements: {
|
||||
textureCache->textureMap.replacementMapEnabled = !textureCache->textureMap.replacementMapEnabled;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void Application::end() {
|
||||
# if SCRIPT_ENABLED
|
||||
|
@ -51,6 +51,13 @@ namespace RT64 {
|
||||
GraphicsDeviceNotFound
|
||||
};
|
||||
|
||||
enum class DeveloperShortcut {
|
||||
Inspector,
|
||||
RayTracing,
|
||||
ViewRDRAM,
|
||||
Replacements
|
||||
};
|
||||
|
||||
struct Core {
|
||||
RenderWindow window;
|
||||
uint8_t *HEADER;
|
||||
@ -159,8 +166,10 @@ namespace RT64 {
|
||||
bool checkDirectoryCreated(const std::filesystem::path &path);
|
||||
# ifdef _WIN32
|
||||
bool windowMessageFilter(unsigned int message, WPARAM wParam, LPARAM lParam) override;
|
||||
bool usesWindowMessageFilter() override;
|
||||
# endif
|
||||
bool sdlEventFilter(SDL_Event *event) override;
|
||||
bool usesWindowMessageFilter() override;
|
||||
void processDeveloperShortcut(DeveloperShortcut developerShortcut);
|
||||
void updateUserConfig(bool discardFBs);
|
||||
void updateEmulatorConfig();
|
||||
void updateEnhancementConfig();
|
||||
|
@ -51,16 +51,24 @@ namespace RT64 {
|
||||
assert(listener != nullptr);
|
||||
|
||||
this->listener = listener;
|
||||
windowHandle = window;
|
||||
|
||||
# ifdef _WIN32
|
||||
windowHandle = window;
|
||||
usingSdl = SDL_WasInit(SDL_INIT_VIDEO);
|
||||
|
||||
if (listener->usesWindowMessageFilter()) {
|
||||
assert(HookedApplicationWindow == nullptr);
|
||||
assert(threadId != 0);
|
||||
windowHook = SetWindowsHookEx(WH_GETMESSAGE, &windowHookCallback, NULL, threadId);
|
||||
HookedApplicationWindow = this;
|
||||
if (usingSdl) {
|
||||
// We'd normally install the event filter here, but Mupen does not set its own event filter
|
||||
// until much later. Instead, we delegate this to the first time a screen update is sent.
|
||||
}
|
||||
# ifdef _WIN32
|
||||
else {
|
||||
assert(HookedApplicationWindow == nullptr);
|
||||
assert(threadId != 0);
|
||||
windowHook = SetWindowsHookEx(WH_GETMESSAGE, &windowHookCallback, NULL, threadId);
|
||||
HookedApplicationWindow = this;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void ApplicationWindow::setup(const char *windowTitle, Listener *listener) {
|
||||
@ -71,7 +79,7 @@ namespace RT64 {
|
||||
const int Height = 720;
|
||||
struct {
|
||||
uint32_t left, top, width, height;
|
||||
} bounds {};
|
||||
} bounds{};
|
||||
|
||||
# if defined(_WIN32)
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
@ -108,9 +116,8 @@ namespace RT64 {
|
||||
# else
|
||||
static_assert(false && "Unimplemented");
|
||||
# endif
|
||||
|
||||
|
||||
// Create window.
|
||||
#ifdef RT64_SDL_WINDOW
|
||||
SDL_Window *sdlWindow = SDL_CreateWindow(windowTitle, bounds.left, bounds.top, bounds.width, bounds.height, SDL_WINDOW_RESIZABLE);
|
||||
SDL_SysWMinfo wmInfo;
|
||||
assert(sdlWindow && "Failed to open window with SDL");
|
||||
@ -128,10 +135,6 @@ namespace RT64 {
|
||||
# else
|
||||
static_assert(false && "Unimplemented");
|
||||
# endif
|
||||
usingSdl = true;
|
||||
#else
|
||||
static_assert(false && "Unimplemented");
|
||||
#endif
|
||||
|
||||
# ifdef _WIN32
|
||||
setup(windowHandle, listener, GetCurrentThreadId());
|
||||
@ -305,7 +308,7 @@ namespace RT64 {
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
void ApplicationWindow::windowMessage(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (listener->windowMessageFilter(message, wParam, lParam)) {
|
||||
return;
|
||||
@ -326,47 +329,34 @@ namespace RT64 {
|
||||
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
# endif
|
||||
|
||||
#ifdef RT64_SDL_WINDOW
|
||||
void ApplicationWindow::blockSdlKeyboard() {
|
||||
if (!usingSdl) {
|
||||
return;
|
||||
}
|
||||
|
||||
sdlEventFilterStored = SDL_GetEventFilter(&sdlEventFilter, &sdlEventFilterUserdata);
|
||||
if (sdlEventFilterStored) {
|
||||
SDL_SetEventFilter(&ApplicationWindow::sdlEventKeyboardFilter, this);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationWindow::unblockSdlKeyboard() {
|
||||
if (!usingSdl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdlEventFilterStored) {
|
||||
SDL_SetEventFilter(sdlEventFilter, sdlEventFilterUserdata);
|
||||
sdlEventFilterStored = false;
|
||||
}
|
||||
}
|
||||
|
||||
int ApplicationWindow::sdlEventKeyboardFilter(void *userdata, SDL_Event *event) {
|
||||
ApplicationWindow *appWindow = reinterpret_cast<ApplicationWindow *>(userdata);
|
||||
|
||||
switch (event->type) {
|
||||
// Ignore all keyboard events.
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
return 0;
|
||||
// Pass through to the original event filter.
|
||||
default:
|
||||
return appWindow->sdlEventFilter(userdata, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
static_assert(false && "Unimplemented");
|
||||
#endif
|
||||
|
||||
void ApplicationWindow::sdlCheckFilterInstallation() {
|
||||
if (!sdlEventFilterInstalled && usingSdl) {
|
||||
if (!SDL_GetEventFilter(&sdlEventFilterStored, &sdlEventFilterUserdata)) {
|
||||
sdlEventFilterStored = nullptr;
|
||||
sdlEventFilterUserdata = nullptr;
|
||||
}
|
||||
|
||||
SDL_SetEventFilter(&ApplicationWindow::sdlEventFilter, this);
|
||||
sdlEventFilterInstalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
int ApplicationWindow::sdlEventFilter(void *userdata, SDL_Event *event) {
|
||||
// Run it through the listener's event filter. If it's processed by the listener, the event should be filtered.
|
||||
ApplicationWindow *appWindow = reinterpret_cast<ApplicationWindow *>(userdata);
|
||||
if (appWindow->listener->sdlEventFilter(event)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pass to the event filter that was stored if it exists. Let the original filter determine the result.
|
||||
if (appWindow->sdlEventFilterStored != nullptr) {
|
||||
return appWindow->sdlEventFilterStored(appWindow->sdlEventFilterUserdata, event);
|
||||
}
|
||||
// The event should not be filtered.
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -9,34 +9,29 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define RT64_SDL_WINDOW
|
||||
|
||||
#ifdef RT64_SDL_WINDOW
|
||||
# include "SDL_events.h"
|
||||
# include "SDL_system.h"
|
||||
# include "SDL_syswm.h"
|
||||
# include "SDL_video.h"
|
||||
#endif
|
||||
#include "SDL.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_system.h"
|
||||
#include "SDL_syswm.h"
|
||||
#include "SDL_video.h"
|
||||
|
||||
namespace RT64 {
|
||||
struct ApplicationWindow {
|
||||
static ApplicationWindow *HookedApplicationWindow;
|
||||
|
||||
struct Listener {
|
||||
virtual bool usesWindowMessageFilter() = 0;
|
||||
|
||||
// Return true if the listener should accept and handle the message.
|
||||
// Return false otherwise for the default message handler to take over.
|
||||
virtual bool sdlEventFilter(SDL_Event *event) = 0;
|
||||
|
||||
# ifdef _WIN32
|
||||
virtual bool windowMessageFilter(unsigned int message, WPARAM wParam, LPARAM lParam) = 0;
|
||||
virtual bool usesWindowMessageFilter() = 0;
|
||||
# endif
|
||||
};
|
||||
|
||||
RenderWindow windowHandle;
|
||||
# ifdef _WIN32
|
||||
HHOOK windowHook;
|
||||
HMENU windowMenu;
|
||||
RECT lastWindowRect;
|
||||
# endif
|
||||
Listener *listener;
|
||||
uint32_t refreshRate = 0;
|
||||
bool fullScreen;
|
||||
@ -44,6 +39,15 @@ namespace RT64 {
|
||||
bool usingSdl;
|
||||
int32_t windowLeft = INT32_MAX;
|
||||
int32_t windowTop = INT32_MAX;
|
||||
SDL_EventFilter sdlEventFilterStored = nullptr;
|
||||
void *sdlEventFilterUserdata = nullptr;
|
||||
bool sdlEventFilterInstalled = false;
|
||||
|
||||
# ifdef _WIN32
|
||||
HHOOK windowHook;
|
||||
HMENU windowMenu;
|
||||
RECT lastWindowRect;
|
||||
# endif
|
||||
|
||||
ApplicationWindow();
|
||||
~ApplicationWindow();
|
||||
@ -54,20 +58,12 @@ namespace RT64 {
|
||||
void detectRefreshRate();
|
||||
uint32_t getRefreshRate() const;
|
||||
bool detectWindowMoved();
|
||||
void sdlCheckFilterInstallation();
|
||||
static int sdlEventFilter(void *userdata, SDL_Event *event);
|
||||
|
||||
# ifdef _WIN32
|
||||
void windowMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
static LRESULT windowHookCallback(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
# endif
|
||||
|
||||
# ifdef RT64_SDL_WINDOW
|
||||
SDL_EventFilter sdlEventFilter;
|
||||
void *sdlEventFilterUserdata;
|
||||
bool sdlEventFilterStored;
|
||||
|
||||
void blockSdlKeyboard();
|
||||
void unblockSdlKeyboard();
|
||||
static int sdlEventKeyboardFilter(void *userdata, SDL_Event *event);
|
||||
# endif
|
||||
};
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user