#include "imgui/imgui_impl_glfw.h" #include "imgui/imgui_impl_opengl3.h" #include "imgui/imgui_impl_opengl3_loader.h" #include #include #include #include #include #include "Backend.hpp" #include "RunQueue.hpp" static GLFWwindow* s_window; static std::function s_redraw; static RunQueue* s_mainThreadTasks; static WindowPosition* s_winPos; static void glfw_error_callback( int error, const char* description ) { fprintf(stderr, "Error %d: %s\n", error, description); } static void glfw_window_pos_callback( GLFWwindow* window, int x, int y ) { if( !glfwGetWindowAttrib( window, GLFW_MAXIMIZED ) ) { s_winPos->x = x; s_winPos->y = y; } } static void glfw_window_size_callback( GLFWwindow* window, int w, int h ) { if( !glfwGetWindowAttrib( window, GLFW_MAXIMIZED ) ) { s_winPos->w = w; s_winPos->h = h; } } static void glfw_window_maximize_callback( GLFWwindow*, int maximized ) { s_winPos->maximize = maximized; } Backend::Backend( const char* title, std::function redraw, RunQueue* mainThreadTasks ) { glfwSetErrorCallback( glfw_error_callback ); if( !glfwInit() ) exit( 1 ); #ifdef DISPLAY_SERVER_WAYLAND glfwWindowHint( GLFW_ALPHA_BITS, 0 ); #else glfwWindowHint(GLFW_VISIBLE, 0 ); #endif glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 2 ); glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); #if __APPLE__ glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE ); #endif s_window = glfwCreateWindow( m_winPos.w, m_winPos.h, title, NULL, NULL ); if( !s_window ) exit( 1 ); glfwSetWindowPos( s_window, m_winPos.x, m_winPos.y ); #ifdef GLFW_MAXIMIZED if( m_winPos.maximize ) glfwMaximizeWindow( s_window ); #endif glfwMakeContextCurrent( s_window ); glfwSwapInterval( 1 ); // Enable vsync glfwSetWindowRefreshCallback( s_window, []( GLFWwindow* ) { s_redraw(); } ); ImGui_ImplGlfw_InitForOpenGL( s_window, true ); ImGui_ImplOpenGL3_Init( "#version 150" ); s_redraw = redraw; s_mainThreadTasks = mainThreadTasks; s_winPos = &m_winPos; glfwSetWindowPosCallback( s_window, glfw_window_pos_callback ); glfwSetWindowSizeCallback( s_window, glfw_window_size_callback ); glfwSetWindowMaximizeCallback( s_window, glfw_window_maximize_callback ); } Backend::~Backend() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); glfwDestroyWindow( s_window ); glfwTerminate(); } void Backend::Show() { glfwShowWindow( s_window ); } void Backend::Run() { while( !glfwWindowShouldClose( s_window ) ) { glfwPollEvents(); if( glfwGetWindowAttrib( s_window, GLFW_ICONIFIED ) ) { std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); continue; } s_redraw(); if( !glfwGetWindowAttrib( s_window, GLFW_FOCUSED ) ) { std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); } s_mainThreadTasks->Run(); } } void Backend::NewFrame( int& w, int& h ) { glfwGetFramebufferSize( s_window, &w, &h ); m_w = w; m_h = h; ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); } void Backend::EndFrame() { const ImVec4 clear_color = ImColor( 114, 144, 154 ); ImGui::Render(); glViewport( 0, 0, m_w, m_h ); glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w ); glClear( GL_COLOR_BUFFER_BIT ); ImGui_ImplOpenGL3_RenderDrawData( ImGui::GetDrawData() ); // Update and Render additional Platform Windows // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) if( ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) { GLFWwindow* backup_current_context = glfwGetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); glfwMakeContextCurrent( backup_current_context ); } glfwSwapBuffers( s_window ); } void Backend::SetIcon( uint8_t* data, int w, int h ) { GLFWimage icon; icon.width = w; icon.height = h; icon.pixels = data; glfwSetWindowIcon( s_window, 1, &icon ); } void Backend::SetTitle( const char* title ) { glfwSetWindowTitle( s_window, title ); } float Backend::GetDpiScale() { #if GLFW_VERSION_MAJOR > 3 || ( GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3 ) auto monitor = glfwGetWindowMonitor( s_window ); if( !monitor ) monitor = glfwGetPrimaryMonitor(); if( monitor ) { float x, y; glfwGetMonitorContentScale( monitor, &x, &y ); return x; } #endif return 1; }