From 1e4279f6711ce2601f367e10a6a6254cf92cf16f Mon Sep 17 00:00:00 2001 From: rexy712 Date: Thu, 24 Feb 2022 19:04:27 -0800 Subject: [PATCH] Move basic window functionality to a superclass. Makes it easier to share implementation with other concrete windows using GLFW --- include/gfx/{init.hpp => glfw_init.hpp} | 17 +-- include/gfx/ogl/window.hpp | 71 +-------- include/gfx/window.hpp | 104 +++++++++++++ src/gfx/{init.cpp => glfw_init.cpp} | 42 +++--- src/gfx/ogl/window.cpp | 186 +---------------------- src/gfx/window.cpp | 192 ++++++++++++++++++++++++ 6 files changed, 344 insertions(+), 268 deletions(-) rename include/gfx/{init.hpp => glfw_init.hpp} (73%) create mode 100644 include/gfx/window.hpp rename src/gfx/{init.cpp => glfw_init.cpp} (58%) create mode 100644 src/gfx/window.cpp diff --git a/include/gfx/init.hpp b/include/gfx/glfw_init.hpp similarity index 73% rename from include/gfx/init.hpp rename to include/gfx/glfw_init.hpp index e23d542..3b69756 100644 --- a/include/gfx/init.hpp +++ b/include/gfx/glfw_init.hpp @@ -1,6 +1,6 @@ /** - This file is a part of our_dick - Copyright (C) 2020 rexy712 + This file is a part of vulkan + Copyright (C) 2022 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,26 +16,25 @@ along with this program. If not, see . */ -#ifndef OUR_DICK_GRAPHICS_INIT_HPP -#define OUR_DICK_GRAPHICS_INIT_HPP +#ifndef VULKAN_GRAPHICS_GLFW_SYSTEM_HPP +#define VULKAN_GRAPHICS_GLFW_SYSTEM_HPP #include namespace gfx{ - //initializer/deinitializer for glfw class glfw_system { private: - static inline int s_status = 0; - static inline std::mutex s_ref_count_mtx = {}; - static inline int s_ref_count = 0; + static inline std::mutex s_ref_lock; + static inline int s_ref_count; + static inline int s_status = false; public: glfw_system(void); ~glfw_system(void); int status(void)const; }; -} +} #endif diff --git a/include/gfx/ogl/window.hpp b/include/gfx/ogl/window.hpp index 3a0ab93..6b75296 100644 --- a/include/gfx/ogl/window.hpp +++ b/include/gfx/ogl/window.hpp @@ -20,20 +20,17 @@ #define OUR_DICK_GRAPHICS_OGL_WINDOW_HPP #include "gl_include.hpp" -#include "../init.hpp" +#include "gfx/glfw_init.hpp" #include -#include "util/init_constants.hpp" + +#include "gfx/window.hpp" + +#include namespace gfx::ogl{ - class window + class window : public ::gfx::window { - public: - enum class mousemode : int{ - DISABLED, - HIDDEN, - NORMAL, - }; private: //opengl 4.5 has been supported since intel broadwell, nvidia 400 series, and radeon hd 5000 //should be supported on any system I care about @@ -41,9 +38,7 @@ namespace gfx::ogl{ static constexpr int s_default_cver_min = 5; private: - GLFWwindow* m_window = nullptr; - glfw_system m_glfw_handle; - char* m_title = nullptr; + std::string m_title = {}; int m_antialias_level = 0; int m_refresh_rate = GLFW_DONT_CARE; int m_swap_interval = 1; @@ -53,73 +48,23 @@ namespace gfx::ogl{ window(int context_vmaj, int context_vmin, int width, int height, const char* title, bool make_current = true, int antialias = 0, int refresh = GLFW_DONT_CARE); window(const window&); window(window&&); - ~window(void); + ~window(void) = default; window& operator=(const window&); window& operator=(window&&); - GLFWwindow* raw(void); - const GLFWwindow* raw(void)const; - - operator GLFWwindow*(void); - operator const GLFWwindow*(void)const; - void make_current(void); void swap_buffers(void); - void destroy(void); - - void set_size(const rml::vec2i&); - void set_size(int w, int h); - void set_width(int w); - void set_height(int h); - void set_title(const char* t); - void set_pos(const rml::vec2i&); - void set_pos(int x, int y); - void set_x(int x); - void set_y(int y); - - void set_visible(bool b = true); - void toggle_visible(void); - void set_resizable(bool b = true); - void set_decorated(bool b = true); - void set_always_on_top(bool b = true); void set_antialias(int level); void set_refresh_rate(int rate); void set_swap_interval(int i); - void set_should_close(bool b = true); - void set_mousemode(mousemode m); - - void set_key_callback(void); - //TODO callbacks void set_active(void); - - rml::vec2i get_size(void)const; - int get_width(void)const; - int get_height(void)const; - - rml::vec2i get_pos(void)const; - int get_posx(void)const; - int get_posy(void)const; - rml::vec2i get_context_version(void)const; int get_context_vmaj(void)const; int get_context_vmin(void)const; int get_swap_interval(void)const; - - rml::vec2d get_cursor_pos(void)const; - double get_cursor_posx(void)const; - double get_cursor_posy(void)const; - bool get_key(int key, int action)const; - - bool is_visible(void)const; - bool is_resizable(void)const; - bool is_decorated(void)const; - bool is_always_on_top(void)const; - bool is_fullscreen(void)const; - bool should_close(void)const; - mousemode get_mousemode(void)const; }; } diff --git a/include/gfx/window.hpp b/include/gfx/window.hpp new file mode 100644 index 0000000..bd0494b --- /dev/null +++ b/include/gfx/window.hpp @@ -0,0 +1,104 @@ +/** + This file is a part of our_dick + Copyright (C) 2022 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef OUR_DICK_GRAPHICS_WINDOW_HPP +#define OUR_DICK_GRAPHICS_WINDOW_HPP + +#include "glfw_init.hpp" +#include +#include + +namespace gfx{ + + class window + { + public: + enum class mousemode : int{ + DISABLED, + HIDDEN, + NORMAL, + }; + protected: + GLFWwindow* m_window = nullptr; + glfw_system m_glfw_handle; + + protected: + window(void); + window(const window&) = delete; //Implement in derived classes + window(window&&); + ~window(void); + + window& operator=(const window&) = delete; //Implement in derived classes + window& operator=(window&&); + + public: + GLFWwindow* raw(void); + const GLFWwindow* raw(void)const; + + operator GLFWwindow*(void); + operator const GLFWwindow*(void)const; + + void destroy(void); + + void set_size(const rml::vec2i&); + void set_size(int w, int h); + void set_width(int w); + void set_height(int h); + void set_title(const char* t); + void set_pos(const rml::vec2i&); + void set_pos(int x, int y); + void set_x(int x); + void set_y(int y); + + void set_visible(bool b = true); + void toggle_visible(void); + void set_resizable(bool b = true); + void set_decorated(bool b = true); + void set_always_on_top(bool b = true); + void set_antialias(int level); + void set_should_close(bool b = true); + void set_mousemode(mousemode m); + + void set_key_callback(void); + //TODO callbacks + + + rml::vec2i get_size(void)const; + int get_width(void)const; + int get_height(void)const; + + rml::vec2i get_pos(void)const; + int get_posx(void)const; + int get_posy(void)const; + + rml::vec2d get_cursor_pos(void)const; + double get_cursor_posx(void)const; + double get_cursor_posy(void)const; + bool get_key(int key, int action)const; + + bool is_visible(void)const; + bool is_resizable(void)const; + bool is_decorated(void)const; + bool is_always_on_top(void)const; + bool is_fullscreen(void)const; + bool should_close(void)const; + }; + +} + +#endif diff --git a/src/gfx/init.cpp b/src/gfx/glfw_init.cpp similarity index 58% rename from src/gfx/init.cpp rename to src/gfx/glfw_init.cpp index 3be481a..8f5df42 100644 --- a/src/gfx/init.cpp +++ b/src/gfx/glfw_init.cpp @@ -1,6 +1,6 @@ /** - This file is a part of our_dick - Copyright (C) 2020 rexy712 + This file is a part of vulkan + Copyright (C) 2022 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -16,43 +16,49 @@ along with this program. If not, see . */ -#include "gfx/init.hpp" +#include "gfx/glfw_init.hpp" #include "config.hpp" -#include "gfx/ogl/gl_include.hpp" - #include //lock_guard, mutex +#include namespace gfx{ -#ifdef OUR_DICK_ENABLE_DEBUG_OUTPUT - static void our_dick_glfw_error_callback(int code, const char* description){ +#ifdef VULKAN_ENABLE_DEBUG + static void glfw_error_callback_(int code, const char* description){ rexy::debug::print_error("%d: %s\n", code, description); } -#endif +#endif //VULKAN_ENABLE_DEBUG glfw_system::glfw_system(void){ - { - std::lock_guard lk(s_ref_count_mtx); - ++s_ref_count; - } + std::lock_guard lk(s_ref_lock); + ++s_ref_count; if(s_status){ rexy::debug::print_warn("Call to glfwInit after already initialized\n"); return; } -#ifdef OUR_DICK_ENABLE_DEBUG_OUTPUT - glfwSetErrorCallback(our_dick_glfw_error_callback); -#endif +#ifdef VULKAN_ENABLE_DEBUG + glfwSetErrorCallback(glfw_error_callback_); +#endif //VULKAN_ENABLE_DEBUG s_status = glfwInit(); + if(s_status != GLFW_TRUE) + rexy::debug::verbose::print_error("Failed to initialize GLFW\n"); + else + rexy::debug::verbose::print_succ("Initialized GLFW\n"); + } glfw_system::~glfw_system(void){ - std::lock_guard lk(s_ref_count_mtx); + std::lock_guard lk(s_ref_lock); --s_ref_count; - if(!s_ref_count) + if(!s_ref_count){ + rexy::debug::verbose::print("Terminating GLFW\n"); glfwTerminate(); + } } int glfw_system::status(void)const{ - return s_status; + std::lock_guard lk(s_ref_lock); + int i = s_status; + return i; } } diff --git a/src/gfx/ogl/window.cpp b/src/gfx/ogl/window.cpp index 5c99cd3..25ffe09 100644 --- a/src/gfx/ogl/window.cpp +++ b/src/gfx/ogl/window.cpp @@ -17,11 +17,10 @@ */ #include "gfx/ogl/window.hpp" -#include "gfx/init.hpp" +#include "gfx/glfw_init.hpp" #include "gfx/backend_check.hpp" -#include //exchange, swap, pair -#include //strlen, strncpy +#include //move #include "config.hpp" namespace gfx::ogl{ @@ -140,24 +139,10 @@ static void enable_opengl_debug_context(void){ return false; } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-truncation" -#endif - static char* copy_title(const char* src, size_t titlelen){ - char* dest = new char[titlelen + 1]; - strncpy(dest, src, titlelen); - dest[titlelen] = 0; - return dest; - } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - window::window(int width, int height, const char* title, bool makecurrent): window(s_default_cver_maj, s_default_cver_min, width, height, title, makecurrent){} window::window(int cver_maj, int cver_min, int width, int height, const char* title, bool makecurrent, int antialias, int refresh): - m_title(copy_title(title, strlen(title))), + m_title(title), m_antialias_level(antialias), m_refresh_rate(refresh) { @@ -171,16 +156,6 @@ static void enable_opengl_debug_context(void){ #else glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_FALSE); #endif - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); - glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); - - //GLFW cannot open hidden window on wayland currently (glfw v3.3.4) - if(backend::is_wayland_display()){ - glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); - }else{ - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); - } glfwWindowHint(GLFW_REFRESH_RATE, m_refresh_rate); glfwWindowHint(GLFW_SAMPLES, m_antialias_level); @@ -221,14 +196,13 @@ static void enable_opengl_debug_context(void){ glfwMakeContextCurrent(current_context); } window::window(const window& w): - m_title(copy_title(w.m_title, strlen(w.m_title))), + ::gfx::window(), + m_title(w.m_title), m_antialias_level(w.m_antialias_level), m_refresh_rate(w.m_refresh_rate), m_swap_interval(w.m_swap_interval) { - copy_title(w.m_title, strlen(w.m_title)); - #ifdef OUR_DICK_ENABLE_DEBUG_CONTEXT glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); #else @@ -253,7 +227,7 @@ static void enable_opengl_debug_context(void){ glfwWindowHint(GLFW_SAMPLES, w.m_antialias_level); auto size = w.get_size(); - m_window = glfwCreateWindow(size.x(), size.y(), m_title, nullptr, nullptr); + m_window = glfwCreateWindow(size.x(), size.y(), m_title.c_str(), nullptr, nullptr); if(!m_window){ rexy::debug::print_error("Unable to create a GLFW window!\n"); destroy(); @@ -280,39 +254,21 @@ static void enable_opengl_debug_context(void){ set_visible(w.is_visible()); } window::window(window&& w): - m_window(std::exchange(w.m_window, nullptr)), - m_title(std::exchange(w.m_title, nullptr)), + m_title(std::move(w.m_title)), m_antialias_level(w.m_antialias_level), m_refresh_rate(w.m_refresh_rate), m_swap_interval(w.m_swap_interval){} - window::~window(void){ - destroy(); - } window& window::operator=(const window& w){ return (*this = window(w)); } window& window::operator=(window&& w){ - std::swap(m_window, w.m_window); + ::gfx::window::operator=(std::move(w)); m_antialias_level = w.m_antialias_level; m_refresh_rate = w.m_refresh_rate; m_swap_interval = w.m_swap_interval; return *this; } - GLFWwindow* window::raw(void){ - return m_window; - } - const GLFWwindow* window::raw(void)const{ - return m_window; - } - - window::operator GLFWwindow*(void){ - return m_window; - } - window::operator const GLFWwindow*(void)const{ - return m_window; - } - void window::make_current(void){ glfwMakeContextCurrent(m_window); @@ -321,64 +277,6 @@ static void enable_opengl_debug_context(void){ glfwSwapBuffers(m_window); } - void window::destroy(void){ - if(m_window) - glfwDestroyWindow(m_window); - m_window = nullptr; - - delete[] m_title; - m_title = nullptr; - } - - void window::set_size(const rml::vec2i& v){ - set_size(v.x(), v.y()); - } - void window::set_size(int w, int h){ - glfwSetWindowSize(m_window, w, h); - } - void window::set_width(int w){ - set_size(w, get_height()); - } - void window::set_height(int h){ - set_size(get_width(), h); - } - void window::set_title(const char* t){ - glfwSetWindowTitle(m_window, t); - } - void window::set_pos(const rml::vec2i& v){ - set_pos(v.x(), v.y()); - } - void window::set_pos(int x, int y){ - glfwSetWindowPos(m_window, x, y); - } - void window::set_x(int x){ - set_pos(x, get_posy()); - } - void window::set_y(int y){ - set_pos(get_posx(), y); - } - - void window::set_visible(bool b){ - if(b) - glfwShowWindow(m_window); - else - glfwHideWindow(m_window); - } - void window::toggle_visible(void){ - if(is_visible()) - glfwHideWindow(m_window); - else - glfwShowWindow(m_window); - } - void window::set_resizable(bool b){ - glfwSetWindowAttrib(m_window, GLFW_RESIZABLE, b); - } - void window::set_decorated(bool b){ - glfwSetWindowAttrib(m_window, GLFW_DECORATED, b); - } - void window::set_always_on_top(bool b){ - glfwSetWindowAttrib(m_window, GLFW_FLOATING, b); - } void window::set_antialias(int level){ m_antialias_level = level; } @@ -392,42 +290,11 @@ static void enable_opengl_debug_context(void){ glfwMakeContextCurrent(current_context); } - void window::set_should_close(bool b){ - glfwSetWindowShouldClose(m_window, b); - } -/* - void window::set_mousemode(mousemode m){ - //TODO - } -*/ void window::set_active(void){ glfwMakeContextCurrent(m_window); } - rml::vec2i window::get_size(void)const{ - rml::vec2i retval; - glfwGetWindowSize(m_window, &retval.x(), &retval.y()); - return retval; - } - int window::get_width(void)const{ - return get_size().x(); - } - int window::get_height(void)const{ - return get_size().y(); - } - - rml::vec2i window::get_pos(void)const{ - rml::vec2i retval; - glfwGetWindowPos(m_window, &retval.x(), &retval.y()); - return retval; - } - int window::get_posx(void)const{ - return get_pos().x(); - } - int window::get_posy(void)const{ - return get_pos().y(); - } rml::vec2i window::get_context_version(void)const{ return rml::vec2i{get_context_vmaj(), get_context_vmin()}; } @@ -441,41 +308,4 @@ static void enable_opengl_debug_context(void){ return m_swap_interval; } - rml::vec2d window::get_cursor_pos(void)const{ - rml::vec2d retval; - glfwGetCursorPos(m_window, &retval.x(), &retval.y()); - return retval; - } - double window::get_cursor_posx(void)const{ - return get_cursor_pos().x(); - } - double window::get_cursor_posy(void)const{ - return get_cursor_pos().y(); - } - bool window::get_key(int key, int action)const{ - return glfwGetKey(m_window, key) == action; - } - - bool window::is_visible(void)const{ - return glfwGetWindowAttrib(m_window, GLFW_VISIBLE); - } - bool window::is_resizable(void)const{ - return glfwGetWindowAttrib(m_window, GLFW_RESIZABLE); - } - bool window::is_decorated(void)const{ - return glfwGetWindowAttrib(m_window, GLFW_DECORATED); - } - bool window::is_always_on_top(void)const{ - return glfwGetWindowAttrib(m_window, GLFW_FLOATING); - } - bool window::should_close(void)const{ - return glfwWindowShouldClose(m_window); - } -/* bool window::is_fullscreen(void)const{ - //TODO - } - auto window::get_mousemode(void)const -> mousemode{ - //TODO - } -*/ } diff --git a/src/gfx/window.cpp b/src/gfx/window.cpp new file mode 100644 index 0000000..e2cd7a7 --- /dev/null +++ b/src/gfx/window.cpp @@ -0,0 +1,192 @@ +/** + This file is a part of our_dick + Copyright (C) 2020-2022 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#include "gfx/window.hpp" +#include "gfx/glfw_init.hpp" +#include "gfx/backend_check.hpp" +#include "config.hpp" + +#include //exchange, swap + +namespace gfx{ + + window::window(void){ + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); + glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); + + //GLFW cannot open hidden window on wayland currently (glfw v3.3.4) + if(backend::is_wayland_display()){ + glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); + }else{ + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + } + } + window::window(window&& w): + m_window(std::exchange(w.m_window, nullptr)){} + window::~window(void){ + destroy(); + } + + window& window::operator=(window&& w){ + std::swap(m_window, w.m_window); + return *this; + } + GLFWwindow* window::raw(void){ + return m_window; + } + const GLFWwindow* window::raw(void)const{ + return m_window; + } + + window::operator GLFWwindow*(void){ + return m_window; + } + window::operator const GLFWwindow*(void)const{ + return m_window; + } + + + void window::destroy(void){ + if(m_window) + glfwDestroyWindow(m_window); + m_window = nullptr; + } + + void window::set_size(const rml::vec2i& v){ + set_size(v.x(), v.y()); + } + void window::set_size(int w, int h){ + glfwSetWindowSize(m_window, w, h); + } + void window::set_width(int w){ + set_size(w, get_height()); + } + void window::set_height(int h){ + set_size(get_width(), h); + } + void window::set_title(const char* t){ + glfwSetWindowTitle(m_window, t); + } + void window::set_pos(const rml::vec2i& v){ + set_pos(v.x(), v.y()); + } + void window::set_pos(int x, int y){ + glfwSetWindowPos(m_window, x, y); + } + void window::set_x(int x){ + set_pos(x, get_posy()); + } + void window::set_y(int y){ + set_pos(get_posx(), y); + } + + void window::set_visible(bool b){ + if(b) + glfwShowWindow(m_window); + else + glfwHideWindow(m_window); + } + void window::toggle_visible(void){ + if(is_visible()) + glfwHideWindow(m_window); + else + glfwShowWindow(m_window); + } + void window::set_resizable(bool b){ + glfwSetWindowAttrib(m_window, GLFW_RESIZABLE, b); + } + void window::set_decorated(bool b){ + glfwSetWindowAttrib(m_window, GLFW_DECORATED, b); + } + void window::set_always_on_top(bool b){ + glfwSetWindowAttrib(m_window, GLFW_FLOATING, b); + } + + void window::set_should_close(bool b){ + glfwSetWindowShouldClose(m_window, b); + } +/* + void window::set_mousemode(mousemode m){ + //TODO + } +*/ + + + rml::vec2i window::get_size(void)const{ + rml::vec2i retval; + glfwGetWindowSize(m_window, &retval.x(), &retval.y()); + return retval; + } + int window::get_width(void)const{ + return get_size().x(); + } + int window::get_height(void)const{ + return get_size().y(); + } + + rml::vec2i window::get_pos(void)const{ + rml::vec2i retval; + glfwGetWindowPos(m_window, &retval.x(), &retval.y()); + return retval; + } + int window::get_posx(void)const{ + return get_pos().x(); + } + int window::get_posy(void)const{ + return get_pos().y(); + } + + rml::vec2d window::get_cursor_pos(void)const{ + rml::vec2d retval; + glfwGetCursorPos(m_window, &retval.x(), &retval.y()); + return retval; + } + double window::get_cursor_posx(void)const{ + return get_cursor_pos().x(); + } + double window::get_cursor_posy(void)const{ + return get_cursor_pos().y(); + } + bool window::get_key(int key, int action)const{ + return glfwGetKey(m_window, key) == action; + } + + bool window::is_visible(void)const{ + return glfwGetWindowAttrib(m_window, GLFW_VISIBLE); + } + bool window::is_resizable(void)const{ + return glfwGetWindowAttrib(m_window, GLFW_RESIZABLE); + } + bool window::is_decorated(void)const{ + return glfwGetWindowAttrib(m_window, GLFW_DECORATED); + } + bool window::is_always_on_top(void)const{ + return glfwGetWindowAttrib(m_window, GLFW_FLOATING); + } + bool window::should_close(void)const{ + return glfwWindowShouldClose(m_window); + } +/* bool window::is_fullscreen(void)const{ + //TODO + } + auto window::get_mousemode(void)const -> mousemode{ + //TODO + } +*/ +}