diff --git a/CMakeLists.txt b/CMakeLists.txt index a9ed390bd..75cd110e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,12 +54,21 @@ else() set(WITH_JACK_DEFAULT OFF) endif() +set(WITH_RENDER_SDL_DEFAULT ON) +if (APPLE) + set(WITH_RENDER_OPENGL_DEFAULT OFF) +else() + set(WITH_RENDER_OPENGL_DEFAULT ON) +endif() + option(BUILD_GUI "Build the tracker (disable to build only a headless player)" ${BUILD_GUI_DEFAULT}) option(USE_RTMIDI "Build with MIDI support using RtMidi." ${USE_RTMIDI_DEFAULT}) option(USE_SDL2 "Build with SDL2. Required to build with GUI." ${USE_SDL2_DEFAULT}) option(USE_SNDFILE "Build with libsndfile. Required in order to work with audio files." ${USE_SNDFILE_DEFAULT}) option(USE_BACKWARD "Use backward-cpp to print a backtrace on crash/abort." ${USE_BACKWARD_DEFAULT}) option(WITH_JACK "Whether to build with JACK support. Auto-detects if JACK is available" ${WITH_JACK_DEFAULT}) +option(WITH_RENDER_SDL "Whether to build with the SDL_Renderer render backend." ${WITH_RENDER_SDL_DEFAULT}) +option(WITH_RENDER_OPENGL "Whether to build with the OpenGL render backend." ${WITH_RENDER_OPENGL_DEFAULT}) option(SYSTEM_FFTW "Use a system-installed version of FFTW instead of the vendored one" OFF) option(SYSTEM_FMT "Use a system-installed version of fmt instead of the vendored one" OFF) option(SYSTEM_LIBSNDFILE "Use a system-installed version of libsndfile instead of the vendored one" OFF) @@ -92,7 +101,7 @@ set(DEPENDENCIES_LIBRARY_DIRS "") set(DEPENDENCIES_LINK_OPTIONS "") set(DEPENDENCIES_LEGACY_LDFLAGS "") -if (BUILD_GUI) +if (BUILD_GUI AND WITH_RENDER_SDL) set(SYSTEM_SDL_MIN_VER 2.0.18) else() set(SYSTEM_SDL_MIN_VER 2.0.0) @@ -278,6 +287,12 @@ else() endif() endif() +if (BUILD_GUI) + if (NOT WITH_RENDER_SDL AND NOT WITH_RENDER_OPENGL) + message(FATAL_ERROR "No render backends selected!") + endif() +endif() + set(AUDIO_SOURCES src/audio/abstract.cpp src/audio/midi.cpp @@ -580,7 +595,6 @@ extern/imgui_patched/imgui.cpp extern/imgui_patched/imgui_draw.cpp extern/imgui_patched/imgui_tables.cpp extern/imgui_patched/imgui_widgets.cpp -extern/imgui_patched/backends/imgui_impl_sdlrenderer.cpp extern/imgui_patched/backends/imgui_impl_sdl.cpp extern/imgui_patched/misc/cpp/imgui_stdlib.cpp extern/igfd/ImGuiFileDialog.cpp @@ -679,6 +693,25 @@ if (APPLE) list(APPEND GUI_SOURCES extern/nfd-modified/src/nfd_cocoa.mm) endif() +if (WITH_RENDER_SDL) + list(APPEND GUI_SOURCES src/gui/render/renderSDL.cpp) + list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_sdlrenderer.cpp) + list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_SDL) + message(STATUS "UI render backend: SDL_Renderer") +endif() + +if (WITH_RENDER_OPENGL) + list(APPEND GUI_SOURCES src/gui/render/renderGL.cpp) + list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_opengl3.cpp) + list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_GL) + if (WIN32) + list(APPEND DEPENDENCIES_LIBRARIES opengl32) + else() + list(APPEND DEPENDENCIES_LIBRARIES GL) + endif() + message(STATUS "UI render backend: OpenGL") +endif() + if (NOT WIN32 AND NOT APPLE) CHECK_INCLUDE_FILE(sys/io.h SYS_IO_FOUND) CHECK_INCLUDE_FILE(linux/input.h LINUX_INPUT_FOUND) diff --git a/extern/imgui_patched/imgui_impl_sdlrenderer.cpp b/extern/imgui_patched/imgui_impl_sdlrenderer.cpp deleted file mode 100644 index 9da0d488d..000000000 --- a/extern/imgui_patched/imgui_impl_sdlrenderer.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// dear imgui: Renderer Backend for SDL_Renderer -// (Requires: SDL 2.0.17+) - -// Important to understand: SDL_Renderer is an _optional_ component of SDL. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might -// be difficult to step out of those boundaries. -// However, we understand it is a convenient choice to get an app started easily. - -// Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. -// Missing features: -// [ ] Renderer: Multi-viewport support (multiple windows). - -// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. -// Read online: https://github.com/ocornut/imgui/tree/master/docs - -// CHANGELOG -// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19. -// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. -// 2021-10-06: Backup and restore modified ClipRect/Viewport. -// 2021-09-21: Initial version. - -#include "imgui.h" -#include "imgui_impl_sdlrenderer.h" -#include -#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier -#include // intptr_t -#else -#include // intptr_t -#endif - -// SDL -#include -#if !SDL_VERSION_ATLEAST(2,0,17) -#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function -#endif - -// SDL_Renderer data -struct ImGui_ImplSDLRenderer_Data -{ - SDL_Renderer* SDLRenderer; - SDL_Texture* FontTexture; - ImGui_ImplSDLRenderer_Data() { memset(this, 0, sizeof(*this)); } -}; - -// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts -// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. -static ImGui_ImplSDLRenderer_Data* ImGui_ImplSDLRenderer_GetBackendData() -{ - return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer_Data*)ImGui::GetIO().BackendRendererUserData : NULL; -} - -// Functions -bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer) -{ - ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!"); - IM_ASSERT(renderer != NULL && "SDL_Renderer not initialized!"); - - // Setup backend capabilities flags - ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_sdlrenderer"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - - bd->SDLRenderer = renderer; - - return true; -} - -void ImGui_ImplSDLRenderer_Shutdown() -{ - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - - ImGui_ImplSDLRenderer_DestroyDeviceObjects(); - - io.BackendRendererName = NULL; - io.BackendRendererUserData = NULL; - IM_DELETE(bd); -} - -static void ImGui_ImplSDLRenderer_SetupRenderState() -{ - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - - // Clear out any viewports and cliprect set by the user - // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process. - SDL_RenderSetViewport(bd->SDLRenderer, NULL); - SDL_RenderSetClipRect(bd->SDLRenderer, NULL); -} - -bool ImGui_ImplSDLRenderer_NewFrame() -{ - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDLRenderer_Init()?"); - - if (!bd->FontTexture) - return ImGui_ImplSDLRenderer_CreateDeviceObjects(); - - return true; -} - -void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data) -{ - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - - // If there's a scale factor set by the user, use that instead - // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass - // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. - float rsx = 1.0f; - float rsy = 1.0f; - SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy); - ImVec2 render_scale; - render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; - render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; - - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); - int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); - if (fb_width == 0 || fb_height == 0) - return; - - // Backup SDL_Renderer state that will be modified to restore it afterwards - struct BackupSDLRendererState - { - SDL_Rect Viewport; - bool ClipEnabled; - SDL_Rect ClipRect; - }; - BackupSDLRendererState old = {}; - old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE; - SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport); - SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect); - - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = render_scale; - - // Render command lists - ImGui_ImplSDLRenderer_SetupRenderState(); - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplSDLRenderer_SetupRenderState(); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } - if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) }; - SDL_RenderSetClipRect(bd->SDLRenderer, &r); - - const float* xy = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos)); - const float* uv = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv)); -#if SDL_VERSION_ATLEAST(2,0,19) - const SDL_Color* color = (const SDL_Color*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+ -#else - const int* color = (const int*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18 -#endif - - // Bind texture, Draw - SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); - SDL_SetTextureScaleMode(tex, SDL_ScaleModeBest); // ??? - SDL_RenderGeometryRaw(bd->SDLRenderer, tex, - xy, (int)sizeof(ImDrawVert), - color, (int)sizeof(ImDrawVert), - uv, (int)sizeof(ImDrawVert), - cmd_list->VtxBuffer.Size - pcmd->VtxOffset, - idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx)); - } - } - } - - // Restore modified SDL_Renderer state - SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport); - SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : NULL); -} - -// Called by Init/NewFrame/Shutdown -bool ImGui_ImplSDLRenderer_CreateFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - - // Build texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); - if (bd->FontTexture == NULL) - { - SDL_Log("error creating texture"); - return false; - } - SDL_UpdateTexture(bd->FontTexture, NULL, pixels, 4 * width); - SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); - - return true; -} - -void ImGui_ImplSDLRenderer_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData(); - if (bd->FontTexture) - { - io.Fonts->SetTexID(0); - SDL_DestroyTexture(bd->FontTexture); - bd->FontTexture = NULL; - } -} - -bool ImGui_ImplSDLRenderer_CreateDeviceObjects() -{ - return ImGui_ImplSDLRenderer_CreateFontsTexture(); -} - -void ImGui_ImplSDLRenderer_DestroyDeviceObjects() -{ - ImGui_ImplSDLRenderer_DestroyFontsTexture(); -} diff --git a/extern/imgui_patched/imgui_impl_sdlrenderer.h b/extern/imgui_patched/imgui_impl_sdlrenderer.h deleted file mode 100644 index 379265de0..000000000 --- a/extern/imgui_patched/imgui_impl_sdlrenderer.h +++ /dev/null @@ -1,31 +0,0 @@ -// dear imgui: Renderer Backend for SDL_Renderer -// (Requires: SDL 2.0.17+) - -// Important to understand: SDL_Renderer is an _optional_ component of SDL. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might -// be difficult to step out of those boundaries. -// However, we understand it is a convenient choice to get an app started easily. - -// Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. -// Missing features: -// [ ] Renderer: Multi-viewport support (multiple windows). - -#pragma once -#include "imgui.h" // IMGUI_IMPL_API - -struct SDL_Renderer; - -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer_Shutdown(); -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data); - -// Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyFontsTexture(); -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyDeviceObjects(); diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index f697a1421..d7d3c9fd9 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -179,7 +179,7 @@ void FurnaceGUI::drawChanOsc() { ImVec2 gradLeft=ImGui::GetCursorPos(); ImVec2 gradSize=ImVec2(400.0f*dpiScale,400.0f*dpiScale); - ImGui::Image(chanOscGradTex,gradSize); + ImGui::Image(rend->getTextureID(chanOscGradTex),gradSize); ImVec2 gradLeftAbs=ImGui::GetItemRectMin(); if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (chanOscGrad.points.size()<32) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 3781f289e..a6fab88fc 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -30,7 +30,6 @@ #include "imgui.h" #include "imgui_internal.h" #include "imgui_impl_sdl.h" -#include "imgui_impl_sdlrenderer.h" #include "ImGuiFileDialog.h" #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" @@ -3763,7 +3762,7 @@ bool FurnaceGUI::loop() { layoutTimeBegin=SDL_GetPerformanceCounter(); - if (!ImGui_ImplSDLRenderer_NewFrame()) { + if (!rend->newFrame()) { fontsFailed=true; } ImGui_ImplSDL2_NewFrame(sdlWin); @@ -5848,9 +5847,11 @@ bool FurnaceGUI::loop() { ImGui::GetIO().Fonts->Clear(); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); patFont=mainFont; - ImGui_ImplSDLRenderer_DestroyFontsTexture(); + if (rend) rend->destroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { logE("error again while building font atlas!"); + } else { + rend->createFontsTexture(); } } @@ -6116,7 +6117,27 @@ bool FurnaceGUI::init() { logV("window size: %dx%d",scrW,scrH); - sdlWin=SDL_CreateWindow("Furnace",scrX,scrY,scrW,scrH,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(scrMax?SDL_WINDOW_MAXIMIZED:0)|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); + if (!initRender()) { + if (settings.renderBackend=="OpenGL") { + settings.renderBackend=""; + e->setConf("renderBackend",""); + e->saveConf(); + lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); + } else { + lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError()); + if (!settings.renderDriver.empty()) { + settings.renderDriver=""; + e->setConf("renderDriver",""); + e->saveConf(); + lastError=fmt::sprintf("\r\nthe render driver has been set to a safe value. please restart Furnace."); + } + } + return false; + } + + rend->preInit(); + + sdlWin=SDL_CreateWindow("Furnace",scrX,scrY,scrW,scrH,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(scrMax?SDL_WINDOW_MAXIMIZED:0)|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)|rend->getWindowFlags()); if (sdlWin==NULL) { lastError=fmt::sprintf("could not open window! %s",SDL_GetError()); return false; @@ -6180,7 +6201,7 @@ bool FurnaceGUI::init() { SDL_SetHint(SDL_HINT_RENDER_DRIVER,settings.renderDriver.c_str()); } - if (!initRender()) { + if (!rend->init(sdlWin)) { if (settings.renderBackend=="OpenGL") { settings.renderBackend=""; e->setConf("renderBackend",""); @@ -6222,7 +6243,7 @@ bool FurnaceGUI::init() { ImGui::GetIO().Fonts->Clear(); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); patFont=mainFont; - ImGui_ImplSDLRenderer_DestroyFontsTexture(); + if (rend) rend->destroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { logE("error again while building font atlas!"); } @@ -6457,6 +6478,8 @@ bool FurnaceGUI::finish() { FurnaceGUI::FurnaceGUI(): e(NULL), + renderBackend(GUI_BACKEND_SDL), + rend(NULL), sdlWin(NULL), vibrator(NULL), vibratorAvailable(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index ac8908cd3..1fd1e71e2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -24,7 +24,6 @@ #include "../engine/waveSynth.h" #include "imgui.h" #include "imgui_impl_sdl.h" -#include "imgui_impl_sdlrenderer.h" #include #include #include @@ -1227,6 +1226,7 @@ enum FurnaceGUIBlendMode { class FurnaceGUIRender { public: + virtual ImTextureID getTextureID(void* which); virtual bool lockTexture(void* which, void** data, int* pitch); virtual bool unlockTexture(void* which); virtual bool updateTexture(void* which, void* data, int pitch); @@ -1235,10 +1235,15 @@ class FurnaceGUIRender { virtual void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode); virtual void setBlendMode(FurnaceGUIBlendMode mode); virtual void clear(ImVec4 color); + virtual bool newFrame(); + virtual void createFontsTexture(); + virtual void destroyFontsTexture(); virtual void renderGUI(); virtual void wipe(float alpha); virtual void present(); virtual bool getOutputSize(int& w, int& h); + virtual int getWindowFlags(); + virtual void preInit(); virtual bool init(SDL_Window* win); virtual void initGUI(SDL_Window* win); virtual void quitGUI(); diff --git a/src/gui/intro.cpp b/src/gui/intro.cpp index 75cc0fc1b..db886316b 100644 --- a/src/gui/intro.cpp +++ b/src/gui/intro.cpp @@ -69,7 +69,7 @@ void FurnaceGUI::drawImage(ImDrawList* dl, FurnaceGUIImages image, const ImVec2& ImU32 colorConverted=ImGui::GetColorU32(imgColor); - dl->AddImageQuad(img,quad0,quad1,quad2,quad3,uv0,uv1,uv2,uv3,colorConverted); + dl->AddImageQuad(rend->getTextureID(img),quad0,quad1,quad2,quad3,uv0,uv1,uv2,uv3,colorConverted); } void FurnaceGUI::endIntroTune() { diff --git a/src/gui/render.cpp b/src/gui/render.cpp index 069205d50..cc7cdba2f 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -18,13 +18,51 @@ */ #include "gui.h" +#include "../ta-log.h" +#ifdef HAVE_RENDER_SDL #include "render/renderSDL.h" +#endif +#ifdef HAVE_RENDER_GL +#include "render/renderGL.h" +#endif + +#ifdef HAVE_RENDER_SDL +#define GUI_BACKEND_DEFAULT GUI_BACKEND_SDL +#else +#define GUI_BACKEND_DEFAULT GUI_BACKEND_GL +#endif bool FurnaceGUI::initRender() { if (rend!=NULL) return false; + + if (settings.renderBackend=="OpenGL") { + renderBackend=GUI_BACKEND_GL; + } else if (settings.renderBackend=="SDL") { + renderBackend=GUI_BACKEND_SDL; + } else { + renderBackend=GUI_BACKEND_DEFAULT; + } - rend=new FurnaceGUIRenderSDL; - return rend->init(sdlWin); + switch (renderBackend) { +#ifdef HAVE_RENDER_GL + case GUI_BACKEND_GL: + logI("render backend: OpenGL"); + rend=new FurnaceGUIRenderGL; + break; +#endif +#ifdef HAVE_RENDER_SDL + case GUI_BACKEND_SDL: + logI("render backend: SDL_Renderer"); + rend=new FurnaceGUIRenderSDL; + break; +#endif + default: + logE("invalid render backend!"); + return false; + break; + } + + return true; } bool FurnaceGUI::quitRender() { diff --git a/src/gui/render/abstract.cpp b/src/gui/render/abstract.cpp index 69adad0d4..996cf4e86 100644 --- a/src/gui/render/abstract.cpp +++ b/src/gui/render/abstract.cpp @@ -19,6 +19,10 @@ #include "../gui.h" +ImTextureID FurnaceGUIRender::getTextureID(void* which) { + return NULL; +} + bool FurnaceGUIRender::lockTexture(void* which, void** data, int* pitch) { return false; } @@ -48,6 +52,16 @@ void FurnaceGUIRender::setBlendMode(FurnaceGUIBlendMode mode) { void FurnaceGUIRender::clear(ImVec4 color) { } +bool FurnaceGUIRender::newFrame() { + return true; +} + +void FurnaceGUIRender::createFontsTexture() { +} + +void FurnaceGUIRender::destroyFontsTexture() { +} + void FurnaceGUIRender::renderGUI() { } @@ -61,6 +75,13 @@ bool FurnaceGUIRender::getOutputSize(int& w, int& h) { return false; } +int FurnaceGUIRender::getWindowFlags() { + return 0; +} + +void FurnaceGUIRender::preInit() { +} + bool FurnaceGUIRender::init(SDL_Window* win) { return false; } @@ -72,7 +93,7 @@ bool FurnaceGUIRender::quit() { return false; } -void FurnaceGUIRender::quitGUI(){ +void FurnaceGUIRender::quitGUI() { } FurnaceGUIRender::~FurnaceGUIRender() { diff --git a/src/gui/render/renderGL.cpp b/src/gui/render/renderGL.cpp index e69de29bb..1c6e2e2d3 100644 --- a/src/gui/render/renderGL.cpp +++ b/src/gui/render/renderGL.cpp @@ -0,0 +1,365 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "renderGL.h" +#include "../../ta-log.h" +#include "SDL_opengl.h" +#include "backends/imgui_impl_opengl3.h" + +#define C(x) x; if (glGetError()!=GL_NO_ERROR) logW("OpenGL error in %s:%d: " #x,__FILE__,__LINE__); + +PFNGLGENBUFFERSPROC furGenBuffers=NULL; +PFNGLBINDBUFFERPROC furBindBuffer=NULL; +PFNGLBUFFERDATAPROC furBufferData=NULL; +PFNGLVERTEXATTRIBPOINTERPROC furVertexAttribPointer=NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC furEnableVertexAttribArray=NULL; + +PFNGLCREATESHADERPROC furCreateShader=NULL; +PFNGLSHADERSOURCEPROC furShaderSource=NULL; +PFNGLCOMPILESHADERPROC furCompileShader=NULL; +PFNGLGETSHADERIVPROC furGetShaderiv=NULL; +PFNGLATTACHSHADERPROC furAttachShader=NULL; +PFNGLBINDATTRIBLOCATIONPROC furBindAttribLocation=NULL; +PFNGLCREATEPROGRAMPROC furCreateProgram=NULL; +PFNGLLINKPROGRAMPROC furLinkProgram=NULL; +PFNGLGETPROGRAMIVPROC furGetProgramiv=NULL; +PFNGLUSEPROGRAMPROC furUseProgram=NULL; +PFNGLGETUNIFORMLOCATIONPROC furGetUniformLocation=NULL; +PFNGLUNIFORM1FPROC furUniform1f=NULL; +PFNGLGETSHADERINFOLOGPROC furGetShaderInfoLog=NULL; + +struct FurnaceGLTexture { + GLuint id; + int width, height; + unsigned char* lockedData; + FurnaceGLTexture(): + id(0), + width(0), + height(0), + lockedData(NULL) {} +}; + +const char* sh_wipe_srcV= + "#version 130\n" + "in vec4 fur_position;\n" + "void main() {\n" + " gl_Position=fur_position;\n" + "}\n"; + +const char* sh_wipe_srcF= + "#version 130\n" + "uniform float uAlpha;\n" + "out vec4 fur_FragColor;\n" + "void main() {\n" + " fur_FragColor=vec4(0.0,0.0,0.0,uAlpha);\n" + "}\n"; + +bool FurnaceGUIRenderGL::createShader(const char* vertexS, const char* fragmentS, int& vertex, int& fragment, int& program) { + int status; + char infoLog[4096]; + int infoLogLen; + + if (!furCreateShader || !furShaderSource || !furCompileShader || !furGetShaderiv || + !furGetShaderInfoLog || !furCreateProgram || !furAttachShader || !furLinkProgram || + !furBindAttribLocation || !furGetProgramiv) { + logW("I can't compile shaders"); + return false; + } + + vertex=furCreateShader(GL_VERTEX_SHADER); + furShaderSource(vertex,1,&vertexS,NULL); + furCompileShader(vertex); + furGetShaderiv(vertex,GL_COMPILE_STATUS,&status); + if (!status) { + logW("failed to compile vertex shader"); + furGetShaderInfoLog(vertex,4095,&infoLogLen,infoLog); + infoLog[infoLogLen]=0; + logW("%s",infoLog); + return false; + } + + fragment=furCreateShader(GL_FRAGMENT_SHADER); + furShaderSource(fragment,1,&fragmentS,NULL); + furCompileShader(fragment); + furGetShaderiv(fragment,GL_COMPILE_STATUS,&status); + if (!status) { + logW("failed to compile fragment shader"); + return false; + } + + program=furCreateProgram(); + furAttachShader(program,vertex); + furAttachShader(program,fragment); + furBindAttribLocation(program,0,"fur_position"); + furLinkProgram(program); + furGetProgramiv(program,GL_LINK_STATUS,&status); + if (!status) { + logW("failed to link shader!"); + return false; + } + + return true; +} + +ImTextureID FurnaceGUIRenderGL::getTextureID(void* which) { + intptr_t ret=((FurnaceGLTexture*)which)->id; + return (ImTextureID)ret; +} + +bool FurnaceGUIRenderGL::lockTexture(void* which, void** data, int* pitch) { + FurnaceGLTexture* t=(FurnaceGLTexture*)which; + if (t->lockedData!=NULL) return false; + t->lockedData=new unsigned char[t->width*t->height*4]; + + *data=t->lockedData; + *pitch=t->width*4; + return true; +} + +bool FurnaceGUIRenderGL::unlockTexture(void* which) { + FurnaceGLTexture* t=(FurnaceGLTexture*)which; + if (t->lockedData==NULL) return false; + + C(glBindTexture(GL_TEXTURE_2D,t->id)); + C(glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,t->width,t->height,0,GL_RGBA,GL_UNSIGNED_INT_8_8_8_8_REV,t->lockedData)); + + C(glFlush()); + delete[] t->lockedData; + t->lockedData=NULL; + + return true; +} + +bool FurnaceGUIRenderGL::updateTexture(void* which, void* data, int pitch) { + FurnaceGLTexture* t=(FurnaceGLTexture*)which; + + if (t->width*4!=pitch) return false; + + C(glBindTexture(GL_TEXTURE_2D,t->id)); + C(glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,t->width,t->height,0,GL_RGBA,GL_UNSIGNED_INT_8_8_8_8_REV,data)); + return true; +} + +void* FurnaceGUIRenderGL::createTexture(bool dynamic, int width, int height) { + FurnaceGLTexture* t=new FurnaceGLTexture; + C(glGenTextures(1,&t->id)); + C(glBindTexture(GL_TEXTURE_2D,t->id)); + C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)); + C(glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)); + C(glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_INT_8_8_8_8_REV,NULL)); + C(glActiveTexture(GL_TEXTURE0)); + t->width=width; + t->height=height; + return t; +} + +bool FurnaceGUIRenderGL::destroyTexture(void* which) { + FurnaceGLTexture* t=(FurnaceGLTexture*)which; + C(glDeleteTextures(1,&t->id)); + delete t; + return true; +} + +void FurnaceGUIRenderGL::setTextureBlendMode(void* which, FurnaceGUIBlendMode mode) { +} + +void FurnaceGUIRenderGL::setBlendMode(FurnaceGUIBlendMode mode) { + switch (mode) { + case GUI_BLEND_MODE_NONE: + C(glBlendFunc(GL_ONE,GL_ZERO)); + C(glDisable(GL_BLEND)); + break; + case GUI_BLEND_MODE_BLEND: + C(glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)); + C(glEnable(GL_BLEND)); + break; + case GUI_BLEND_MODE_ADD: + C(glBlendFunc(GL_SRC_ALPHA,GL_ONE)); + C(glEnable(GL_BLEND)); + break; + case GUI_BLEND_MODE_MULTIPLY: + C(glBlendFunc(GL_ZERO,GL_SRC_COLOR)); + C(glEnable(GL_BLEND)); + break; + } +} + +void FurnaceGUIRenderGL::clear(ImVec4 color) { + SDL_GL_MakeCurrent(sdlWin,context); + C(glClearColor(color.x,color.y,color.z,color.w)); + C(glClear(GL_COLOR_BUFFER_BIT)); +} + +bool FurnaceGUIRenderGL::newFrame() { + ImGui_ImplOpenGL3_NewFrame(); + return true; +} + +void FurnaceGUIRenderGL::createFontsTexture() { + ImGui_ImplOpenGL3_CreateFontsTexture(); +} + +void FurnaceGUIRenderGL::destroyFontsTexture() { + ImGui_ImplOpenGL3_DestroyFontsTexture(); +} + +void FurnaceGUIRenderGL::renderGUI() { + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +void FurnaceGUIRenderGL::wipe(float alpha) { + C(glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)); + C(glEnable(GL_BLEND)); + + quadVertex[0][0]=-1.0f; + quadVertex[0][1]=-1.0f; + quadVertex[0][2]=0.0f; + quadVertex[1][0]=1.0f; + quadVertex[1][1]=-1.0f; + quadVertex[1][2]=0.0f; + quadVertex[2][0]=-1.0f; + quadVertex[2][1]=1.0f; + quadVertex[2][2]=0.0f; + quadVertex[3][0]=1.0f; + quadVertex[3][1]=1.0f; + quadVertex[3][2]=0.0f; + + C(furBindBuffer(GL_ARRAY_BUFFER,quadBuf)); + C(furBufferData(GL_ARRAY_BUFFER,sizeof(quadVertex),quadVertex,GL_STATIC_DRAW)); + C(furVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,NULL)); + C(furEnableVertexAttribArray(0)); + C(glActiveTexture(GL_TEXTURE0)); + C(glBindTexture(GL_TEXTURE_2D,0)); + if (furUseProgram && furUniform1f) { + C(furUseProgram(sh_wipe_program)); + C(furUniform1f(sh_wipe_uAlpha,alpha)); + } + C(glDrawArrays(GL_TRIANGLE_STRIP,0,4)); +} + +void FurnaceGUIRenderGL::present() { + SDL_GL_SwapWindow(sdlWin); + C(glFinish()); +} + +bool FurnaceGUIRenderGL::getOutputSize(int& w, int& h) { + SDL_GL_GetDrawableSize(sdlWin,&w,&h); + return true; +} + +int FurnaceGUIRenderGL::getWindowFlags() { + return SDL_WINDOW_OPENGL; +} + +void FurnaceGUIRenderGL::preInit() { +#if defined(USE_GLES) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,0); +#elif defined(__APPLE__) + // not recommended... + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS,0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,0); +#endif + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE,8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,24); +} + +#define LOAD_PROC_MANDATORY(_v,_t,_s) \ + _v=(_t)SDL_GL_GetProcAddress(_s); \ + if (!_v) { \ + logE(_s " not found"); \ + return false; \ + } + +#define LOAD_PROC_OPTIONAL(_v,_t,_s) \ + _v=(_t)SDL_GL_GetProcAddress(_s); \ + if (!_v) { \ + logW(_s " not found"); \ + } + +bool FurnaceGUIRenderGL::init(SDL_Window* win) { + sdlWin=win; + context=SDL_GL_CreateContext(win); + if (context==NULL) { + return false; + } + SDL_GL_MakeCurrent(win,context); + SDL_GL_SetSwapInterval(1); + + LOAD_PROC_MANDATORY(furGenBuffers,PFNGLGENBUFFERSPROC,"glGenBuffers"); + LOAD_PROC_MANDATORY(furBindBuffer,PFNGLBINDBUFFERPROC,"glBindBuffer"); + LOAD_PROC_MANDATORY(furBufferData,PFNGLBUFFERDATAPROC,"glBufferData"); + LOAD_PROC_MANDATORY(furVertexAttribPointer,PFNGLVERTEXATTRIBPOINTERPROC,"glVertexAttribPointer"); + LOAD_PROC_MANDATORY(furEnableVertexAttribArray,PFNGLENABLEVERTEXATTRIBARRAYPROC,"glEnableVertexAttribArray"); + + LOAD_PROC_OPTIONAL(furCreateShader,PFNGLCREATESHADERPROC,"glCreateShader"); + LOAD_PROC_OPTIONAL(furShaderSource,PFNGLSHADERSOURCEPROC,"glShaderSource"); + LOAD_PROC_OPTIONAL(furCompileShader,PFNGLCOMPILESHADERPROC,"glCompileShader"); + LOAD_PROC_OPTIONAL(furGetShaderiv,PFNGLGETSHADERIVPROC,"glGetShaderiv"); + LOAD_PROC_OPTIONAL(furAttachShader,PFNGLATTACHSHADERPROC,"glAttachShader"); + LOAD_PROC_OPTIONAL(furBindAttribLocation,PFNGLBINDATTRIBLOCATIONPROC,"glBindAttribLocation"); + LOAD_PROC_OPTIONAL(furCreateProgram,PFNGLCREATEPROGRAMPROC,"glCreateProgram"); + LOAD_PROC_OPTIONAL(furLinkProgram,PFNGLLINKPROGRAMPROC,"glLinkProgram"); + LOAD_PROC_OPTIONAL(furGetProgramiv,PFNGLGETPROGRAMIVPROC,"glGetProgramiv"); + LOAD_PROC_OPTIONAL(furUseProgram,PFNGLUSEPROGRAMPROC,"glUseProgram"); + LOAD_PROC_OPTIONAL(furGetUniformLocation,PFNGLGETUNIFORMLOCATIONPROC,"glGetUniformLocation"); + LOAD_PROC_OPTIONAL(furUniform1f,PFNGLUNIFORM1FPROC,"glUniform1f"); + LOAD_PROC_OPTIONAL(furGetShaderInfoLog,PFNGLGETSHADERINFOLOGPROC,"glGetShaderInfoLog"); + + + if (createShader(sh_wipe_srcV,sh_wipe_srcF,sh_wipe_vertex,sh_wipe_fragment,sh_wipe_program)) { + sh_wipe_uAlpha=furGetUniformLocation(sh_wipe_program,"uAlpha"); + } + + C(furGenBuffers(1,&quadBuf)); + return true; +} + +void FurnaceGUIRenderGL::initGUI(SDL_Window* win) { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGui_ImplSDL2_InitForOpenGL(win,context); + ImGui_ImplOpenGL3_Init(); +} + +bool FurnaceGUIRenderGL::quit() { + if (context==NULL) return false; + SDL_GL_DeleteContext(context); + context=NULL; + return true; +} + +void FurnaceGUIRenderGL::quitGUI() { + ImGui_ImplOpenGL3_Shutdown(); +} \ No newline at end of file diff --git a/src/gui/render/renderGL.h b/src/gui/render/renderGL.h index e69de29bb..6f824a036 100644 --- a/src/gui/render/renderGL.h +++ b/src/gui/render/renderGL.h @@ -0,0 +1,65 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * 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 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "../gui.h" + +class FurnaceGUIRenderGL: public FurnaceGUIRender { + SDL_GLContext context; + SDL_Window* sdlWin; + float quadVertex[4][3]; + unsigned int quadBuf; + + // SHADERS // + // -> wipe + int sh_wipe_vertex; + int sh_wipe_fragment; + int sh_wipe_program; + int sh_wipe_uAlpha; + + bool createShader(const char* vertexS, const char* fragmentS, int& vertex, int& fragment, int& program); + + public: + ImTextureID getTextureID(void* which); + bool lockTexture(void* which, void** data, int* pitch); + bool unlockTexture(void* which); + bool updateTexture(void* which, void* data, int pitch); + void* createTexture(bool dynamic, int width, int height); + bool destroyTexture(void* which); + void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode); + void setBlendMode(FurnaceGUIBlendMode mode); + void clear(ImVec4 color); + bool newFrame(); + void createFontsTexture(); + void destroyFontsTexture(); + void renderGUI(); + void wipe(float alpha); + void present(); + bool getOutputSize(int& w, int& h); + int getWindowFlags(); + void preInit(); + bool init(SDL_Window* win); + void initGUI(SDL_Window* win); + void quitGUI(); + bool quit(); + FurnaceGUIRenderGL(): + context(NULL), + sdlWin(NULL) { + memset(quadVertex,0,4*3*sizeof(float)); + } +}; \ No newline at end of file diff --git a/src/gui/render/renderSDL.cpp b/src/gui/render/renderSDL.cpp index aea055a46..0eb6271ae 100644 --- a/src/gui/render/renderSDL.cpp +++ b/src/gui/render/renderSDL.cpp @@ -18,6 +18,11 @@ */ #include "renderSDL.h" +#include "backends/imgui_impl_sdlrenderer.h" + +ImTextureID FurnaceGUIRenderSDL::getTextureID(void* which) { + return which; +} bool FurnaceGUIRenderSDL::lockTexture(void* which, void** data, int* pitch) { return SDL_LockTexture((SDL_Texture*)which,NULL,data,pitch)==0; @@ -80,6 +85,18 @@ void FurnaceGUIRenderSDL::clear(ImVec4 color) { SDL_RenderClear(sdlRend); } +bool FurnaceGUIRenderSDL::newFrame() { + return ImGui_ImplSDLRenderer_NewFrame(); +} + +void FurnaceGUIRenderSDL::createFontsTexture() { + ImGui_ImplSDLRenderer_CreateFontsTexture(); +} + +void FurnaceGUIRenderSDL::destroyFontsTexture() { + ImGui_ImplSDLRenderer_DestroyFontsTexture(); +} + void FurnaceGUIRenderSDL::renderGUI() { ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData()); } @@ -98,6 +115,13 @@ bool FurnaceGUIRenderSDL::getOutputSize(int& w, int& h) { return SDL_GetRendererOutputSize(sdlRend,&w,&h)==0; } +int FurnaceGUIRenderSDL::getWindowFlags() { + return 0; +} + +void FurnaceGUIRenderSDL::preInit() { +} + bool FurnaceGUIRenderSDL::init(SDL_Window* win) { sdlRend=SDL_CreateRenderer(win,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE); return (sdlRend!=NULL); diff --git a/src/gui/render/renderSDL.h b/src/gui/render/renderSDL.h index d6071b2a8..afae3b3cc 100644 --- a/src/gui/render/renderSDL.h +++ b/src/gui/render/renderSDL.h @@ -22,6 +22,7 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender { SDL_Renderer* sdlRend; public: + ImTextureID getTextureID(void* which); bool lockTexture(void* which, void** data, int* pitch); bool unlockTexture(void* which); bool updateTexture(void* which, void* data, int pitch); @@ -30,10 +31,15 @@ class FurnaceGUIRenderSDL: public FurnaceGUIRender { void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode); void setBlendMode(FurnaceGUIBlendMode mode); void clear(ImVec4 color); + bool newFrame(); + void createFontsTexture(); + void destroyFontsTexture(); void renderGUI(); void wipe(float alpha); void present(); bool getOutputSize(int& w, int& h); + int getWindowFlags(); + void preInit(); bool init(SDL_Window* win); void initGUI(SDL_Window* win); void quitGUI(); diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 301c3b8b2..c0691f7de 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1223,7 +1223,7 @@ void FurnaceGUI::drawSampleEdit() { updateSampleTex=false; } - ImGui::ImageButton(sampleTex,avail,ImVec2(0,0),ImVec2(1,1),0); + ImGui::ImageButton(rend->getTextureID(sampleTex),avail,ImVec2(0,0),ImVec2(1,1),0); ImVec2 rectMin=ImGui::GetItemRectMin(); ImVec2 rectMax=ImGui::GetItemRectMax(); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e2a30e35a..943646d5e 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2711,6 +2711,7 @@ void FurnaceGUI::syncSettings() { settings.orderButtonPos=e->getConfInt("orderButtonPos",2); settings.compress=e->getConfInt("compress",1); settings.newPatternFormat=e->getConfInt("newPatternFormat",1); + settings.renderBackend=e->getConfString("renderBackend","SDL"); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -3050,6 +3051,7 @@ void FurnaceGUI::commitSettings() { e->setConf("orderButtonPos",settings.orderButtonPos); e->setConf("compress",settings.compress); e->setConf("newPatternFormat",settings.newPatternFormat); + e->setConf("renderBackend",settings.renderBackend); // colors for (int i=0; idestroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { logE("error while building font atlas!"); showError("error while loading fonts! please check your settings."); ImGui::GetIO().Fonts->Clear(); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); patFont=mainFont; - ImGui_ImplSDLRenderer_DestroyFontsTexture(); + if (rend) rend->destroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { logE("error again while building font atlas!"); + } else { + rend->createFontsTexture(); } + } else { + rend->createFontsTexture(); } }