Factor out AppGLFW base class

The intention here is to get rid of scaffolding in the consumer
application class and allow to focus on the "important bits".
This commit is contained in:
Maximilian Kueffner
2025-08-17 21:30:00 +02:00
parent e21ddb1246
commit 88cc7363c6
12 changed files with 225 additions and 123 deletions
+198
View File
@@ -0,0 +1,198 @@
#include "AppGLFW.hpp"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include "uiresources_app.h"
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}
void pixelarium::application::AppGLFW::InitMainWindow()
{
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
{
return;
}
// Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GL ES 2.0 + GLSL 100
const char* glsl_version = "#version 100";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
// GL 3.2 + GLSL 150
const char* glsl_version = "#version 150";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#else
// GL 3.0 + GLSL 130
#ifdef __linux__
const char* glsl_version = "#version 130";
#else
const char* glsl_version = reinterpret_cast<const char*>("#version 130");
#endif
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
// glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+
// only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
#endif
// int count;
// GLFWmonitor** monitors = glfwGetMonitors(&count); // at [0] is always the
// main monitor GLFWmonitor* monitor = monitors[1];
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
int xpos, ypos, width, height;
glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height);
// lg::Logger::Info("screen width " + std::to_string(width) +
// " screen heigth " + std::to_string(height));
// Create window with graphics context
window = glfwCreateWindow(1200, 800, PIXELARIUM_TITLE, nullptr, nullptr);
if (window == nullptr)
{
// lg::Logger::Error("no window");
return;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform
// Windows
// io.ConfigViewportsNoAutoMerge = true;
// io.ConfigViewportsNoTaskBarIcon = true;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
}
int pixelarium::application::AppGLFW::RunInternal()
{
ImGuiIO& io = ImGui::GetIO();
(void)io;
while (!glfwWindowShouldClose(this->window))
{
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::DockSpaceOverViewport(ImGui::GetID("Backspace"));
this->MenuBar();
this->Run();
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(this->window, &display_w, &display_h);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
glfwSwapBuffers(this->window);
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(this->window);
glfwTerminate();
return 0;
}
void pixelarium::application::AppGLFW::MenuBar()
{
if (ImGui::BeginMainMenuBar())
{
// main menu
if (ImGui::BeginMenu(MAINMENUNAME))
{
if (ImGui::BeginCombo(LOGLEVELSELECT, LOGLEVELS[log_level_].data()))
{
for (int n = 0; n < static_cast<int>(LOGLEVELS.size()); n++)
{
bool is_selected = (LOGLEVELS[log_level_] == LOGLEVELS[n]);
if (ImGui::Selectable(LOGLEVELS[n].data(), is_selected))
{
log_level_ = n;
this->logger_.ChangeLevel(static_cast<utils::log::LogLevel>(1 << log_level_));
}
if (is_selected) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// consumer main menu bar entries
this->MenuBarOptionsColumn1();
ImGui::EndMenu();
}
// consumer menu bar columns
this->MenuBarOptionsColumn2();
this->MenuBarOptionsColumn3();
this->MenuBarOptionsColumn4();
this->MenuBarOptionsColumn5();
ImGui::EndMainMenuBar();
}
}
void pixelarium::application::AppGLFW::LogLevelSelect()
{
if (ImGui::BeginCombo(LOGLEVELSELECT, LOGLEVELS[log_level_].data()))
{
for (int n = 0; n < static_cast<int>(LOGLEVELS.size()); n++)
{
bool is_selected = (LOGLEVELS[log_level_] == LOGLEVELS[n]);
if (ImGui::Selectable(LOGLEVELS[n].data(), is_selected))
{
log_level_ = n;
this->logger_.ChangeLevel(static_cast<utils::log::LogLevel>(1 << log_level_));
}
if (is_selected) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <GLFW/glfw3.h>
#include <memory>
#include "imgui.h"
#include "utilities/ILog.hpp"
namespace pixelarium::application
{
class AppGLFW
{
public:
explicit AppGLFW(std::unique_ptr<utils::log::ILog>& log) : logger_(*log) { this->InitMainWindow(); }
void Start() { this->RunInternal(); }
protected:
virtual void MenuBarOptionsColumn1() {}
virtual void MenuBarOptionsColumn2() {}
virtual void MenuBarOptionsColumn3() {}
virtual void MenuBarOptionsColumn4() {}
virtual void MenuBarOptionsColumn5() {}
virtual void Run() {}
utils::log::ILog& logger_;
private:
int RunInternal();
void InitMainWindow();
void MenuBar();
void LogLevelSelect();
int log_level_{0};
GLFWwindow* window = nullptr;
ImGuiWindowFlags window_flags_ = 0;
};
} // namespace pixelarium::application
+36
View File
@@ -0,0 +1,36 @@
set(imgui_DIR ${PROJECT_SOURCE_DIR}/modules/imgui)
# set(glfw_DIR ${PROJECT_SOURCE_DIR}/modules/glfw)
message(STATUS "IMGUI:\t" ${imgui_DIR})
# message(STATUS "GLFW:\t" ${glfw_DIR})
# add_directory(${glfw_DIR})
set(PIXELARIUM_TITLE ${CMAKE_PROJECT_NAME})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/uiresources_app.h.in
${CMAKE_BINARY_DIR}/uiresources_app.h @ONLY)
set(APPLIBSRC
AppGLFW.cpp
${imgui_DIR}/imgui.cpp
${imgui_DIR}/imgui_demo.cpp
${imgui_DIR}/imgui_draw.cpp
${imgui_DIR}/imgui_tables.cpp
${imgui_DIR}/imgui_widgets.cpp
${imgui_DIR}/backends/imgui_impl_opengl3.cpp
${imgui_DIR}/backends/imgui_impl_glfw.cpp)
set(APPLIBNAME pixelariumapplicationlib)
add_library(${APPLIBNAME}
STATIC ${APPLIBSRC})
target_link_libraries(${APPLIBNAME}
PRIVATE pixelariumutilslib)
target_include_directories(${APPLIBNAME}
PUBLIC ${CMAKE_BINARY_DIR}
PUBLIC ${PROJECT_SOURCE_DIR}/lib
PUBLIC ${imgui_DIR}
PUBLIC ${imgui_DIR}/backends
PUBLIC ${glfw_INCLUDE_DIR})
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <array>
#include <string_view>
#cmakedefine PIXELARIUM_TITLE "@PIXELARIUM_TITLE@"
#define MAINMENUNAME "Menu"
#define FILEMENUNAME "File"
#define LOGLEVELSELECT "Log Level"
inline constexpr std::array<std::string_view, 5> LOGLEVELS = {"Trace", "Debug", "Info", "Warning", "Error"};