commit a8ebc7a78f9a1951276acbd69ecb5ce1267f3c33 Author: Pcornat Date: Sat May 24 19:07:31 2025 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dfe7fc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +cmake-* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..330faa0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,67 @@ +cmake_minimum_required(VERSION 4.0) +project(WindowGlfwGlLib CXX C) + +include(CheckIPOSupported) +check_ipo_supported(RESULT IS_IPO_SUPPORTED OUTPUT IPO_OUTPUT_VERBOSE) + +find_package(OpenGL REQUIRED) +find_package(GLEW REQUIRED) +find_package(glfw3 REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(Jemalloc REQUIRED jemalloc) + +set(COMPILE_FLAGS + -pipe + -march=native + -mtune=native + -Wall + -Wextra + -Winline + -pedantic + -pedantic-errors + -Wnrvo +) + +set(COMPILE_OPTIMIZED_FLAGS + -fno-plt + -fuse-ld=mold + -funroll-loops + -ffunction-sections + -fdata-sections + -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free +) + +set(LINKER_OPTIONS + -Wl,--sort-common,--as-needed +) + +set(LINKER_OPTIMIZED_OPTIONS + -Wl,--gc-sections + -fuse-ld=mold +) +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + set(COMPILE_FLAGS -stdlib=libc++ ${COMPILE_FLAGS}) + set(LINKER_FLAGS ${LINKER_FLAGS} c++) + + set(COMPILE_OPTIMIZED_FLAGS ${COMPILE_OPTIMIZED_FLAGS} -fwhole-program-vtables) + set(LINKER_OPTIMIZED_OPTIONS ${LINKER_OPTIMIZED_OPTIONS} -fwhole-program-vtables) +elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + set(LINKER_FLAGS ${LINKER_FLAGS} stdc++) + + set(COMPILE_OPTIMIZED_FLAGS ${COMPILE_OPTIMIZED_FLAGS} -fdevirtualize-at-ltrans) + set(LINKER_OPTIMIZED_OPTIONS ${LINKER_OPTIMIZED_OPTIONS} -fdevirtualize-at-ltrans) +endif () + +add_library(WindowGlfwGlLib SHARED window.cpp window.hpp basic_data.hpp) +target_precompile_headers(${PROJECT_NAME} PUBLIC window.hpp basic_data.hpp) +target_compile_definitions(${PROJECT_NAME} PUBLIC GLFW_INCLUDE_NONE PRIVATE $<$,$>:_GLIBCXX_DEBUG>) +target_compile_options(${PROJECT_NAME} PUBLIC ${COMPILE_FLAGS} $<$:${COMPILE_OPTIMIZED_FLAGS}>) +target_link_options(${PROJECT_NAME} PUBLIC ${LINKER_OPTIONS} $<$:${LINKER_OPTIMIZED_OPTIONS}>) +target_link_libraries(${PROJECT_NAME} PUBLIC $<$:${Jemalloc_LIBRARIES}> OpenGL::GL GLEW::GLEW glfw) + +set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 23 CXX_EXTENSIONS OFF) +if(IS_IPO_SUPPORTED) + set_property(TARGET ${PROJECT_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) +else() + message(WARNING "IPO is not supported: ${IPO_OUTPUT_VERBOSE}") +endif() diff --git a/basic_data.hpp b/basic_data.hpp new file mode 100644 index 0000000..cbe279a --- /dev/null +++ b/basic_data.hpp @@ -0,0 +1,33 @@ +#ifndef POC2DMODULAR_BASIC_DATA_HPP +#define POC2DMODULAR_BASIC_DATA_HPP + + +#include +#include + +namespace data { + class BasicData { + public: + + const std::string name{ "Basic" }; + + BasicData() = delete; + + explicit BasicData(std::string name) : name(std::move(name)) {} + + virtual ~BasicData() noexcept = default; + + virtual void key_callback(int key, int scancode, int action, int mods) = 0; + + virtual void cursor_position_callback(double xpos, double ypos) = 0; + + virtual void scroll_callback(double xoffset, double yoffset) = 0; + + virtual void window_pos(int xpos, int ypos) = 0; + + virtual void window_size(int width, int height) = 0; + }; +} + + +#endif //POC2DMODULAR_BASIC_DATA_HPP diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000..6c79e0a --- /dev/null +++ b/window.cpp @@ -0,0 +1,157 @@ +#include "window.hpp" +#include +#include + +static void internalFramebufferCallback([[maybe_unused]] GLFWwindow *glfWwindow, const int width, const int height) { + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +namespace gui { + static bool init = false; + + std::uint_fast8_t Window::count_instance = 0; + + Window::Window(const bool debugOpengl, + const GLFWframebuffersizefun framebufferCallback, + GLFWwindow *shared, + const std::initializer_list initializer) : modules(initializer) { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, debugOpengl ? GLFW_TRUE : GLFW_FALSE); + wwindow = std::unique_ptr( + glfwCreateWindow(720, 1280, "Billy Sheet tracker", nullptr, shared), + delete_glfw_window + ); + if (!wwindow) { + glfwTerminate(); + init = false; + count_instance = 0; + return; + } + glfwMakeContextCurrent(wwindow.get()); + glewExperimental = true; + if (glewInit() != GLEW_OK) { + wwindow.reset(nullptr); + glfwTerminate(); + init = false; + count_instance = 0; + return; + } + ++count_instance; + glfwSetFramebufferSizeCallback(wwindow.get(), + framebufferCallback != nullptr ? framebufferCallback : internalFramebufferCallback); + + glfwSwapInterval(1); // VSync on + glfwSetKeyCallback(wwindow.get(), key_callback); + glfwSetScrollCallback(wwindow.get(), scroll_callback); + glfwSetCursorPosCallback(wwindow.get(), cursor_position_callback); + glfwSetWindowSizeCallback(wwindow.get(), window_size_callback); + glfwSetWindowPosCallback(wwindow.get(), window_pos_callback); + glfwSetWindowUserPointer(wwindow.get(), &modules); + } + + Window::~Window() noexcept { + if (count_instance > 0) { + --count_instance; + } + } + + const std::unique_ptr &Window::get_window() const noexcept { + return wwindow; + } + + bool Window::should_close() const noexcept { + return glfwWindowShouldClose(wwindow.get()); + } + + void Window::swap_buffers() const noexcept { + glfwSwapBuffers(wwindow.get()); + } + + void Window::key_callback(GLFWwindow *window, const int key, const int scancode, const int action, const int mods) { + auto *modules = static_cast(glfwGetWindowUserPointer(window)); + std::ranges::for_each(*modules, + [=](modulesType::reference item) { item.second->key_callback(key, scancode, action, mods); }); + } + + void Window::cursor_position_callback(GLFWwindow *window, const double xpos, const double ypos) { + auto *modules = static_cast(glfwGetWindowUserPointer(window)); + std::ranges::for_each(*modules, + [=](modulesType::reference item) { item.second->cursor_position_callback(xpos, ypos); }); + } + + void Window::scroll_callback(GLFWwindow *window, const double xoffset, const double yoffset) { + auto *modules = static_cast(glfwGetWindowUserPointer(window)); + std::ranges::for_each(*modules, + [=](modulesType::reference item) { item.second->scroll_callback(xoffset, yoffset); }); + } + + void Window::window_size_callback(GLFWwindow *window, const int width, const int height) { + auto *modules = static_cast(glfwGetWindowUserPointer(window)); + std::ranges::for_each(*modules, + [=](modulesType::reference item) { item.second->window_size(width, height); }); + } + + void Window::window_pos_callback(GLFWwindow *window, const int xpos, const int ypos) { + auto *modules = static_cast(glfwGetWindowUserPointer(window)); + std::ranges::for_each(*modules, + [=](modulesType::reference item) { item.second->window_pos(xpos, ypos); }); + } + + void Window::add_module(data::BasicData &module) { + modules.emplace(module.name, &module); + } + + void Window::delete_module(const std::string &module) { + modules.erase(module); + } + + void Window::get_context() const noexcept { + glfwMakeContextCurrent(wwindow.get()); + } + + std::optional create_window( + const GLFWerrorfun errorCallback, + const GLFWframebuffersizefun framebufferCallback, + const bool debugOpengl, + GLFWwindow *shared, + const std::initializer_list initializer + ) noexcept { + if (!init) { + glfwSetErrorCallback(errorCallback); + if (glfwInit() == GLFW_FALSE) { + return std::nullopt; + } + init = true; + } + if (Window win{ debugOpengl, framebufferCallback, shared, initializer }; win.get_window()) { + return win; + } + return std::nullopt; + } + + bool Window::init_glfw(const GLFWerrorfun errorCallback) noexcept { + glfwSetErrorCallback(errorCallback); + init = glfwInit() == GLFW_TRUE; + return init; + } + + void color_10_bits() noexcept { + glfwWindowHint(GLFW_RED_BITS, 10); + glfwWindowHint(GLFW_GREEN_BITS, 10); + glfwWindowHint(GLFW_BLUE_BITS, 10); + } + + bool check_color_depth(const int color_depth) noexcept { + GLint redBits = 0, greenBits = 0, blueBits = 0; + glGetIntegerv(GL_RED_BITS, &redBits); + glGetIntegerv(GL_GREEN_BITS, &greenBits); + glGetIntegerv(GL_BLUE_BITS, &blueBits); + return redBits == color_depth && greenBits == color_depth && blueBits == color_depth; + } + + void opengl_debug() noexcept { + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); + } +} diff --git a/window.hpp b/window.hpp new file mode 100644 index 0000000..7cd5788 --- /dev/null +++ b/window.hpp @@ -0,0 +1,89 @@ +#ifndef POC2DMODULAR_WINDOW_HPP +#define POC2DMODULAR_WINDOW_HPP + +#include +#include +#include +#include +#include + +namespace data { + class BasicData; +} + +namespace gui { + class Window final { + public: + using modulesType = std::unordered_map; + using windowPtr = GLFWwindow *; + + private: + static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods); + + static void cursor_position_callback(GLFWwindow *window, double xpos, double ypos); + + static void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); + + static void window_size_callback(GLFWwindow *window, int width, int height); + + static void window_pos_callback(GLFWwindow *window, int xpos, int ypos); + + static void delete_glfw_window(GLFWwindow *glfWwindow) { + glfwDestroyWindow(glfWwindow); + glfwTerminate(); + } + + static std::uint_fast8_t count_instance; + + std::unique_ptr wwindow{ nullptr, delete_glfw_window }; + + modulesType modules; + + explicit Window(const bool debugOpengl, + const GLFWframebuffersizefun framebufferCallback, + GLFWwindow *shared, + std::initializer_list initializer); + + public: + [[nodiscard]] static bool init_glfw(GLFWerrorfun errorCallback) noexcept; + + Window() noexcept = delete; + + Window(Window &&window) noexcept = default; + + [[nodiscard]] friend std::optional create_window( + const GLFWerrorfun errorCallback, + GLFWframebuffersizefun framebufferCallback, + const bool debugOpengl, + GLFWwindow *shared, + std::initializer_list initializer) noexcept; + + ~Window() noexcept; + + [[nodiscard]] const std::unique_ptr &get_window() const noexcept; + + [[nodiscard]] bool should_close() const noexcept; + + void swap_buffers() const noexcept; + + void add_module(data::BasicData &module); + + void delete_module(const std::string &module); + + /** + * \brief Make window's OpenGL context current + */ + void get_context() const noexcept; + + Window &operator=(Window &&other) noexcept = default; + }; + + void color_10_bits() noexcept; + + bool check_color_depth(int color_depth) noexcept; + + void opengl_debug() noexcept; +} + + +#endif //POC2DMODULAR_WINDOW_HPP