/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "backends/graphics/sdl/sdl-graphics.h" #include "backends/platform/sdl/sdl-sys.h" #include "backends/platform/sdl/sdl.h" #include "backends/events/sdl/sdl-events.h" #include "backends/keymapper/action.h" #include "backends/keymapper/keymap.h" #include "common/config-manager.h" #include "common/fs.h" #include "common/textconsole.h" #include "common/translation.h" #include "graphics/scaler/aspect.h" #ifdef USE_OSD #include "common/translation.h" #endif #ifdef EMSCRIPTEN #include "backends/platform/sdl/emscripten/emscripten.h" #endif #if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(3, 0, 0) #include "backends/imgui/backends/imgui_impl_sdl3.h" #ifdef USE_OPENGL #include "backends/imgui/backends/imgui_impl_opengl3.h" #endif #ifdef USE_IMGUI_SDLRENDERER3 #include "backends/imgui/backends/imgui_impl_sdlrenderer3.h" #endif #elif defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0) #include "backends/imgui/backends/imgui_impl_sdl2.h" #ifdef USE_OPENGL #include "backends/imgui/backends/imgui_impl_opengl3.h" #endif #ifdef USE_IMGUI_SDLRENDERER2 #include "backends/imgui/backends/imgui_impl_sdlrenderer2.h" #endif #endif static void getMouseState(int *x, int *y) { #if SDL_VERSION_ATLEAST(3, 0, 0) float fx, fy; SDL_GetMouseState(&fx, &fy); *x = static_cast(fx); *y = static_cast(fy); #else SDL_GetMouseState(x, y); #endif } SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window) : _eventSource(source), _window(window), _hwScreen(nullptr) #if SDL_VERSION_ATLEAST(2, 0, 0) , _allowWindowSizeReset(false), _hintedWidth(0), _hintedHeight(0), _lastFlags(0) #endif { ConfMan.registerDefault("fullscreen_res", "desktop"); getMouseState(&_cursorX, &_cursorY); } void SdlGraphicsManager::activateManager() { _eventSource->setGraphicsManager(this); // Register the graphics manager as a event observer g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); } void SdlGraphicsManager::deactivateManager() { // Unregister the event observer if (g_system->getEventManager()->getEventDispatcher()) { g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); } _eventSource->setGraphicsManager(nullptr); } SdlGraphicsManager::State SdlGraphicsManager::getState() const { State state; state.screenWidth = getWidth(); state.screenHeight = getHeight(); state.aspectRatio = getFeatureState(OSystem::kFeatureAspectRatioCorrection); state.fullscreen = getFeatureState(OSystem::kFeatureFullscreenMode); state.cursorPalette = getFeatureState(OSystem::kFeatureCursorPalette); state.vsync = getFeatureState(OSystem::kFeatureVSync); #ifdef USE_RGB_COLOR state.pixelFormat = getScreenFormat(); #endif return state; } Common::RotationMode SdlGraphicsManager::getRotationMode() const { #if SDL_VERSION_ATLEAST(2, 0, 0) return Common::parseRotationMode(ConfMan.getInt("rotation_mode")); #else return Common::kRotationNormal; #endif } bool SdlGraphicsManager::setState(const State &state) { beginGFXTransaction(); #ifdef USE_RGB_COLOR // When switching between the SDL and OpenGL graphics manager, the list // of supported format changes. This means that the pixel format in the // state may not be supported. In that case use the preferred supported // pixel format instead. Graphics::PixelFormat format = state.pixelFormat; Common::List supportedFormats = getSupportedFormats(); if (!supportedFormats.empty() && Common::find(supportedFormats.begin(), supportedFormats.end(), format) == supportedFormats.end()) format = supportedFormats.front(); initSize(state.screenWidth, state.screenHeight, &format); #else initSize(state.screenWidth, state.screenHeight, nullptr); #endif setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio); setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen); setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette); setFeatureState(OSystem::kFeatureVSync, state.vsync); if (endGFXTransaction() != OSystem::kTransactionSuccess) { return false; } else { return true; } } Common::Rect SdlGraphicsManager::getPreferredFullscreenResolution() { // Default to the desktop resolution, unless the user has set a // resolution in the configuration file const Common::String &fsres = ConfMan.get("fullscreen_res"); if (fsres != "desktop") { uint newW, newH; int converted = sscanf(fsres.c_str(), "%ux%u", &newW, &newH); if (converted == 2) { return Common::Rect(newW, newH); } else { warning("Could not parse 'fullscreen_res' option: expected WWWxHHH, got %s", fsres.c_str()); } } return _window->getDesktopResolution(); } bool SdlGraphicsManager::defaultGraphicsModeConfig() const { const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain); if (transientDomain && transientDomain->contains("scaler")) { const Common::String &mode = transientDomain->getVal("scaler"); if (!mode.equalsIgnoreCase("default")) { return false; } } const Common::ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain(); if (gameDomain && gameDomain->contains("scaler")) { const Common::String &mode = gameDomain->getVal("scaler"); if (!mode.equalsIgnoreCase("default")) { return false; } } return true; } void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) { #if SDL_VERSION_ATLEAST(2, 0, 0) const bool useDefault = defaultGraphicsModeConfig(); // This gets called from engine before they call initGraphics(), which means we cannot use getScaleFactor() // because the scale factor in the backend has not yet been updated to use the game settings. So directly // read the game settings. This may be -1, which means we want to use the default. Fortunately runGame() // in main.cpp sets the gaphics mode (OpenGL or SurfaceSDL) before starting the engine. So we already have // the correct graphics manager and we can call getDefaultScaleFactor() here. int scale = ConfMan.getInt("scale_factor"); if (scale == -1) { scale = getDefaultScaleFactor(); } int16 bestWidth = 0, bestHeight = 0; const Graphics::ModeList::const_iterator end = modes.end(); for (Graphics::ModeList::const_iterator it = modes.begin(); it != end; ++it) { int16 width = it->width, height = it->height; // TODO: Normalize AR correction by passing a PAR in the mode list // instead of checking the dimensions here like this, since not all // 320x200/640x400 uses are with non-square pixels (e.g. DreamWeb). if (ConfMan.getBool("aspect_ratio")) { if ((width == 320 && height == 200) || (width == 640 && height == 400)) { height = real2Aspect(height); } } if (!useDefault || width <= 320) { width *= scale; height *= scale; } if (bestWidth < width) { bestWidth = width; } if (bestHeight < height) { bestHeight = height; } } _hintedWidth = bestWidth; _hintedHeight = bestHeight; #endif } bool SdlGraphicsManager::showMouse(bool visible) { if (visible == _cursorVisible) { return visible; } bool showCursor = false; if (visible) { // _cursorX and _cursorY are currently always clipped to the active // area, so we need to ask SDL where the system's mouse cursor is // instead int x, y; getMouseState(&x, &y); if (!_activeArea.drawRect.contains(Common::Point(x, y))) { showCursor = true; } } showSystemMouseCursor(showCursor); return WindowedGraphicsManager::showMouse(visible); } bool SdlGraphicsManager::lockMouse(bool lock) { return _window->lockMouse(lock); } bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) { switch (getRotationMode()) { case Common::kRotationNormal: break; case Common::kRotation90: { int x0 = mouse.x, y0 = mouse.y; mouse.x = CLIP(y0, 0, _windowHeight - 1); mouse.y = CLIP(_windowWidth - 1 - x0, 0, _windowWidth - 1); break; } case Common::kRotation180: { mouse.x = CLIP(_windowWidth - 1 - mouse.x, 0, _windowWidth - 1); mouse.y = CLIP(_windowHeight - 1 - mouse.y, 0, _windowHeight - 1); break; } case Common::kRotation270: { int x0 = mouse.x, y0 = mouse.y; mouse.x = CLIP(_windowHeight - 1 - y0, 0, _windowHeight - 1); mouse.y = CLIP(x0, 0, _windowWidth - 1); break; } } bool showCursor = false; // Currently on macOS we need to scale the events for HiDPI screen, but on // Windows we do not. We can find out if we need to do it by querying the // SDL window size vs the SDL drawable size. float dpiScale = _window->getSdlDpiScalingFactor(); mouse.x = (int)(mouse.x * dpiScale + 0.5f); mouse.y = (int)(mouse.y * dpiScale + 0.5f); bool valid = true; if (_activeArea.drawRect.contains(mouse)) { _cursorLastInActiveArea = true; } else { // The right/bottom edges are not part of the drawRect. As the clipping // is done in drawable area coordinates, but the mouse position is set // in window coordinates, we need to subtract as many pixels from the // edges as corresponds to one pixel in the window coordinates. mouse.x = CLIP(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right - (int)(1 * dpiScale + 0.5f)); mouse.y = CLIP(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom - (int)(1 * dpiScale + 0.5f)); if (_window->mouseIsGrabbed() || // Keep the mouse inside the game area during dragging to prevent an // event mismatch where the mouseup event gets lost because it is // performed outside of the game area (_cursorLastInActiveArea && SDL_GetMouseState(nullptr, nullptr) != 0)) { setSystemMousePosition(mouse.x, mouse.y); } else { // Allow the in-game mouse to get a final movement event to the edge // of the window if the mouse was moved out of the game area if (_cursorLastInActiveArea) { _cursorLastInActiveArea = false; } else if (_cursorVisible) { // Keep sending events to the game if the cursor is invisible, // since otherwise if a game lets you skip a cutscene by // clicking and the user moved the mouse outside the active // area, the clicks wouldn't do anything, which would be // confusing valid = false; } if (_cursorVisible) { showCursor = true; } } } showSystemMouseCursor(showCursor); if (valid) { setMousePosition(mouse.x, mouse.y); mouse = convertWindowToVirtual(mouse.x, mouse.y); } return valid; } void SdlGraphicsManager::showSystemMouseCursor(bool visible) { #if SDL_VERSION_ATLEAST(3, 0, 0) if (visible) { SDL_ShowCursor(); } else { SDL_HideCursor(); } #else SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); #endif } void SdlGraphicsManager::setSystemMousePosition(const int x, const int y) { assert(_window); if (!_window->warpMouseInWindow(x, y)) { const Common::Point mouse = convertWindowToVirtual(x, y); _eventSource->fakeWarpMouse(mouse.x, mouse.y); } } void SdlGraphicsManager::notifyActiveAreaChanged() { _window->setMouseRect(_activeArea.drawRect); } void SdlGraphicsManager::handleResizeImpl(const int width, const int height) { _forceRedraw = true; } #if SDL_VERSION_ATLEAST(2, 0, 0) bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint32 flags) { if (!_window) { return false; } Common::RotationMode rotation = getRotationMode(); if (rotation == Common::kRotation90 || rotation == Common::kRotation270) { int w = width, h = height; width = h; height = w; } // width *=3; // height *=3; // We only update the actual window when flags change (which usually means // fullscreen mode is entered/exited), when updates are forced so that we // do not reset the window size whenever a game makes a call to change the // size or pixel format of the internal game surface (since a user may have // resized the game window), or when the launcher is visible (since a user // may change the scaler, which should reset the window size) if (!_window->getSDLWindow() || _lastFlags != flags || _overlayVisible || _allowWindowSizeReset) { #if SDL_VERSION_ATLEAST(3, 0, 0) const bool fullscreen = (flags & (SDL_WINDOW_FULLSCREEN)) != 0; #else const bool fullscreen = (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0; #endif const bool maximized = (flags & SDL_WINDOW_MAXIMIZED); if (!fullscreen && !maximized) { if (_hintedWidth > width) { width = _hintedWidth; } if (_hintedHeight > height) { height = _hintedHeight; } } if (!_window->createOrUpdateWindow(width, height, flags)) { return false; } #if SDL_VERSION_ATLEAST(3, 0, 0) if (fullscreen) { if (!SDL_SetWindowFullscreenMode(_window->getSDLWindow(), NULL)) return false; if (!SDL_SyncWindow(_window->getSDLWindow())) return false; } #endif _lastFlags = flags; _allowWindowSizeReset = false; } return true; } #endif void SdlGraphicsManager::saveScreenshot() { Common::String filename; Common::Path screenshotsPath; OSystem_SDL *sdl_g_system = dynamic_cast(g_system); if (sdl_g_system) screenshotsPath = sdl_g_system->getScreenshotsPath(); // Use the name of the running target as a base for screenshot file names Common::String currentTarget = ConfMan.getActiveDomainName(); #ifdef USE_PNG const char *extension = "png"; #else const char *extension = "bmp"; #endif for (int n = 0;; n++) { filename = Common::String::format("scummvm%s%s-%05d.%s", currentTarget.empty() ? "" : "-", currentTarget.c_str(), n, extension); Common::FSNode file = Common::FSNode(screenshotsPath.appendComponent(filename)); if (!file.exists()) { break; } } if (saveScreenshot(screenshotsPath.appendComponent(filename))) { if (screenshotsPath.empty()) debug("Saved screenshot '%s' in current directory", filename.c_str()); else debug("Saved screenshot '%s' in directory '%s'", filename.c_str(), screenshotsPath.toString(Common::Path::kNativeSeparator).c_str()); #ifdef USE_OSD if (!ConfMan.getBool("disable_saved_screenshot_osd")) displayMessageOnOSD(Common::U32String::format(_("Saved screenshot '%s'"), filename.c_str())); #endif #ifdef EMSCRIPTEN // Users can't access the virtual emscripten filesystem in the browser, so we export the generated screenshot file via OSystem_Emscripten::exportFile. OSystem_Emscripten *emscripten_g_system = dynamic_cast(g_system); emscripten_g_system->exportFile(screenshotsPath.appendComponent(filename)); #endif } else { if (screenshotsPath.empty()) warning("Could not save screenshot in current directory"); else warning("Could not save screenshot in directory '%s'", screenshotsPath.toString(Common::Path::kNativeSeparator).c_str()); #ifdef USE_OSD displayMessageOnOSD(_("Could not save screenshot")); #endif } } bool SdlGraphicsManager::notifyEvent(const Common::Event &event) { if (event.type != Common::EVENT_CUSTOM_BACKEND_ACTION_START) { return false; } switch ((CustomEventAction) event.customType) { case kActionToggleMouseCapture: getWindow()->grabMouse(!getWindow()->mouseIsGrabbed()); return true; case kActionToggleResizableWindow: getWindow()->setResizable(!getWindow()->resizable()); return true; case kActionToggleFullscreen: toggleFullScreen(); return true; case kActionSaveScreenshot: saveScreenshot(); return true; default: return false; } } void SdlGraphicsManager::toggleFullScreen() { /* Don't use g_system for kFeatureOpenGLForGame as it's always supported * We want to check if we are a 3D graphics manager */ bool is3D = hasFeature(OSystem::kFeatureOpenGLForGame); if (!g_system->hasFeature(OSystem::kFeatureFullscreenMode) || (!g_system->hasFeature(OSystem::kFeatureFullscreenToggleKeepsContext) && is3D)) { return; } if (!is3D) beginGFXTransaction(); setFeatureState(OSystem::kFeatureFullscreenMode, !getFeatureState(OSystem::kFeatureFullscreenMode)); if (!is3D) endGFXTransaction(); #ifdef USE_OSD if (getFeatureState(OSystem::kFeatureFullscreenMode)) displayMessageOnOSD(_("Fullscreen mode")); else displayMessageOnOSD(_("Windowed mode")); #endif } Common::Keymap *SdlGraphicsManager::getKeymap() { using namespace Common; Keymap *keymap = new Keymap(Keymap::kKeymapTypeGlobal, "sdl-graphics", _("Graphics")); Action *act; if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) { act = new Action("FULS", _("Toggle fullscreen")); act->addDefaultInputMapping("A+RETURN"); act->addDefaultInputMapping("A+KP_ENTER"); act->setCustomBackendActionEvent(kActionToggleFullscreen); keymap->addAction(act); } act = new Action("CAPT", _("Toggle mouse capture")); act->addDefaultInputMapping("C+m"); act->setCustomBackendActionEvent(kActionToggleMouseCapture); keymap->addAction(act); act = new Action("RSZW", _("Toggle resizable window")); act->addDefaultInputMapping("C+r"); act->setCustomBackendActionEvent(kActionToggleResizableWindow); keymap->addAction(act); act = new Action("SCRS", _("Save screenshot")); act->addDefaultInputMapping("A+s"); act->setCustomBackendActionEvent(kActionSaveScreenshot); keymap->addAction(act); if (hasFeature(OSystem::kFeatureAspectRatioCorrection)) { act = new Action("ASPT", _("Toggle aspect ratio correction")); act->addDefaultInputMapping("C+A+a"); act->setCustomBackendActionEvent(kActionToggleAspectRatioCorrection); keymap->addAction(act); } if (hasFeature(OSystem::kFeatureFilteringMode)) { act = new Action("FILT", _("Toggle linear filtered scaling")); act->addDefaultInputMapping("C+A+f"); act->setCustomBackendActionEvent(kActionToggleFilteredScaling); keymap->addAction(act); } if (hasFeature(OSystem::kFeatureStretchMode)) { act = new Action("STCH", _("Cycle through stretch modes")); act->addDefaultInputMapping("C+A+s"); act->setCustomBackendActionEvent(kActionCycleStretchMode); keymap->addAction(act); } act = new Action("SCL+", _("Increase the scale factor")); act->addDefaultInputMapping("C+A+PLUS"); act->addDefaultInputMapping("C+A+KP_PLUS"); act->setCustomBackendActionEvent(kActionIncreaseScaleFactor); keymap->addAction(act); act = new Action("SCL-", _("Decrease the scale factor")); act->addDefaultInputMapping("C+A+MINUS"); act->addDefaultInputMapping("C+A+KP_MINUS"); act->setCustomBackendActionEvent(kActionDecreaseScaleFactor); keymap->addAction(act); if (hasFeature(OSystem::kFeatureScalers)) { act = new Action("FLTN", _("Switch to the next scaler")); act->addDefaultInputMapping("C+A+0"); act->setCustomBackendActionEvent(kActionNextScaleFilter); keymap->addAction(act); act = new Action("FLTP", _("Switch to the previous scaler")); act->addDefaultInputMapping("C+A+9"); act->setCustomBackendActionEvent(kActionPreviousScaleFilter); keymap->addAction(act); } return keymap; } #if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0) void SdlGraphicsManager::setImGuiCallbacks(const ImGuiCallbacks &callbacks) { if (_imGuiInited) { if (_imGuiCallbacks.cleanup) { _imGuiCallbacks.cleanup(); } _imGuiInited = false; } _imGuiCallbacks = callbacks; if (!_imGuiReady) { return; } if (_imGuiCallbacks.init) { _imGuiCallbacks.init(); } _imGuiInited = true; } void SdlGraphicsManager::initImGui(SDL_Renderer *renderer, void *glContext) { assert(!_imGuiReady); _imGuiInited = false; IMGUI_CHECKVERSION(); if (!ImGui::CreateContext()) { return; } ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking ImGui::StyleColorsDark(); // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. ImGuiStyle& style = ImGui::GetStyle(); style.WindowRounding = 0.0f; style.Colors[ImGuiCol_WindowBg].w = 1.0f; io.IniFilename = nullptr; _imGuiSDLRenderer = nullptr; #ifdef USE_OPENGL if (!_imGuiReady && glContext) { // Only OpenGL and GLES2 are supported, not GLES if ((OpenGLContext.type != OpenGL::kContextGL) && (OpenGLContext.type != OpenGL::kContextGLES2)) { ImGui::DestroyContext(); return; } io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows #if SDL_VERSION_ATLEAST(3, 0, 0) if (!ImGui_ImplSDL3_InitForOpenGL(_window->getSDLWindow(), glContext)) { #else if (!ImGui_ImplSDL2_InitForOpenGL(_window->getSDLWindow(), glContext)) { #endif ImGui::DestroyContext(); return; } const char *glslVersion; if (OpenGLContext.type == OpenGL::kContextGLES2) { glslVersion = "#version 100"; } else { glslVersion = "#version 110"; } if (!ImGui_ImplOpenGL3_Init(glslVersion)) { #if SDL_VERSION_ATLEAST(3, 0, 0) ImGui_ImplSDL3_Shutdown(); #else ImGui_ImplSDL2_Shutdown(); #endif ImGui::DestroyContext(); return; } _imGuiReady = true; } #endif #ifdef USE_IMGUI_SDLRENDERER3 if (!_imGuiReady && renderer) { if (!ImGui_ImplSDL3_InitForSDLRenderer(_window->getSDLWindow(), renderer)) { ImGui::DestroyContext(); return; } if (!ImGui_ImplSDLRenderer3_Init(renderer)) { ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); return; } _imGuiReady = true; _imGuiSDLRenderer = renderer; } #elif defined(USE_IMGUI_SDLRENDERER2) if (!_imGuiReady && renderer) { if (!ImGui_ImplSDL2_InitForSDLRenderer(_window->getSDLWindow(), renderer)) { ImGui::DestroyContext(); return; } if (!ImGui_ImplSDLRenderer2_Init(renderer)) { ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); return; } _imGuiReady = true; _imGuiSDLRenderer = renderer; } #endif if (!_imGuiReady) { warning("No ImGui renderer has been found"); ImGui::DestroyContext(); return; } if (_imGuiCallbacks.init) { _imGuiCallbacks.init(); } _imGuiInited = true; } void SdlGraphicsManager::renderImGui() { if (!_imGuiReady || !_imGuiCallbacks.render) { return; } if (!_imGuiInited) { if (_imGuiCallbacks.init) { _imGuiCallbacks.init(); } _imGuiInited = true; } #ifdef USE_IMGUI_SDLRENDERER3 if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer3_NewFrame(); } else { #elif defined(USE_IMGUI_SDLRENDERER2) if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer2_NewFrame(); } else { #endif #ifdef USE_OPENGL ImGui_ImplOpenGL3_NewFrame(); #endif #if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3) } #endif #if SDL_VERSION_ATLEAST(3, 0, 0) ImGui_ImplSDL3_NewFrame(); #else ImGui_ImplSDL2_NewFrame(); #endif ImGui::NewFrame(); _imGuiCallbacks.render(); ImGui::Render(); #ifdef USE_IMGUI_SDLRENDERER3 if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), _imGuiSDLRenderer); } else { #elif defined(USE_IMGUI_SDLRENDERER2) if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), _imGuiSDLRenderer); } else { #endif #ifdef USE_OPENGL ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); SDL_GL_MakeCurrent(backup_current_window, backup_current_context); #endif #if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3) } #endif } void SdlGraphicsManager::destroyImGui() { if (!_imGuiReady) { return; } if (_imGuiCallbacks.cleanup) { _imGuiCallbacks.cleanup(); } _imGuiInited = false; _imGuiReady = false; #ifdef USE_IMGUI_SDLRENDERER3 if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer3_Shutdown(); } else { #elif defined(USE_IMGUI_SDLRENDERER2) if (_imGuiSDLRenderer) { ImGui_ImplSDLRenderer2_Shutdown(); } else { #endif #ifdef USE_OPENGL ImGui_ImplOpenGL3_Shutdown(); #endif #if defined(USE_IMGUI_SDLRENDERER2) || defined(USE_IMGUI_SDLRENDERER3) } #endif #if SDL_VERSION_ATLEAST(3, 0, 0) ImGui_ImplSDL3_Shutdown(); #else ImGui_ImplSDL2_Shutdown(); #endif ImGui::DestroyContext(); } #endif