From 65ce06a080284e6f9b6aea51e6fcb21aa02735ba Mon Sep 17 00:00:00 2001 From: Karn Kaul Date: Fri, 26 Jan 2024 21:36:42 +0530 Subject: [PATCH] Upgrade `App`. - Add `set_window_icon()`. - Add `get_features()`. - [DesktopApp] Add `DisplayMode`. --- CMakeLists.txt | 2 +- example/desktop/main.cpp | 2 +- lib/include/bave/app.hpp | 15 +++++++ lib/include/bave/core/make_bitset.hpp | 17 ++++++++ lib/include/bave/desktop_app.hpp | 15 ++++++- lib/include/bave/graphics/render_device.hpp | 2 + lib/include/bave/input/mods.hpp | 8 ++-- lib/platform/desktop/desktop_app.cpp | 46 +++++++++++++++++++-- lib/src/app.cpp | 6 +++ tools/src/main.cpp | 3 +- 10 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 lib/include/bave/core/make_bitset.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c6c451e..06dc876 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(project_prefix bave) -project(${project_prefix} VERSION 0.2.0) +project(${project_prefix} VERSION 0.3.0) set(is_root_project FALSE) diff --git a/example/desktop/main.cpp b/example/desktop/main.cpp index dc5988f..bde6c94 100644 --- a/example/desktop/main.cpp +++ b/example/desktop/main.cpp @@ -8,7 +8,7 @@ auto main(int argc, char** argv) -> int { auto const create_info = bave::DesktopApp::CreateInfo{ .args = bave::make_args(argc, argv), .title = "BaveExample", - .extent = {720, 1280}, + .mode = bave::Windowed{.extent = {720, 1280}}, .assets_patterns = "assets,example/assets", }; diff --git a/lib/include/bave/app.hpp b/lib/include/bave/app.hpp index 7cc8915..9c1c133 100644 --- a/lib/include/bave/app.hpp +++ b/lib/include/bave/app.hpp @@ -24,6 +24,16 @@ enum struct ErrCode : int { eSuccess = 0, eFailure = 1 }; class App : public PolyPinned { public: + struct Feature { + static constexpr std::size_t resizeable{0}; + static constexpr std::size_t has_title{1}; + static constexpr std::size_t has_icon{2}; + static constexpr std::size_t validation_layers{3}; + + static constexpr std::size_t count_v{8}; + }; + using FeatureFlags = std::bitset; + using Bootloader = std::function(App&)>; explicit App(std::string tag = "App"); @@ -38,6 +48,9 @@ class App : public PolyPinned { auto set_window_size(glm::ivec2 size) -> bool { return do_set_window_size(size); } auto set_framebuffer_size(glm::ivec2 size) -> bool; + auto set_window_icon(std::span bitmaps) -> bool { return do_set_window_icon(bitmaps); } + + [[nodiscard]] auto get_features() const -> FeatureFlags; [[nodiscard]] auto get_data_store() const -> DataStore& { return *m_data_store; } [[nodiscard]] auto get_render_device() const -> RenderDevice& { return do_get_render_device(); } @@ -83,6 +96,7 @@ class App : public PolyPinned { virtual void do_shutdown() = 0; + [[nodiscard]] virtual auto do_get_native_features() const -> FeatureFlags { return {}; } [[nodiscard]] virtual auto do_get_window_size() const -> glm::ivec2 { return do_get_framebuffer_size(); } [[nodiscard]] virtual auto do_get_framebuffer_size() const -> glm::ivec2 = 0; @@ -92,6 +106,7 @@ class App : public PolyPinned { virtual auto do_set_window_size(glm::ivec2 size) -> bool = 0; virtual auto do_set_title(CString /*title*/) -> bool { return false; } + virtual auto do_set_window_icon(std::span /*bitmaps*/) -> bool { return false; } void pre_tick(); diff --git a/lib/include/bave/core/make_bitset.hpp b/lib/include/bave/core/make_bitset.hpp new file mode 100644 index 0000000..650992c --- /dev/null +++ b/lib/include/bave/core/make_bitset.hpp @@ -0,0 +1,17 @@ +#pragma once +#include + +namespace bave { +///! Create a std::bitset with bits set. +template ... I> +constexpr auto make_bitset(I const... bits) -> std::bitset { + auto ret = std::bitset{}; + (ret.set(bits), ...); + return ret; +} +///! Create a std::bitset with bits set. +template ... I> +constexpr auto make_bitset(I const... bits) -> Ret { + return make_bitset(bits...); +} +} // namespace bave diff --git a/lib/include/bave/desktop_app.hpp b/lib/include/bave/desktop_app.hpp index eec1012..7e6ffb8 100644 --- a/lib/include/bave/desktop_app.hpp +++ b/lib/include/bave/desktop_app.hpp @@ -14,14 +14,23 @@ struct GLFWwindow; namespace bave { [[nodiscard]] constexpr auto make_args(int argc, char const* const* argv) -> std::span { return {argv, static_cast(argc)}; } +struct Windowed { + glm::ivec2 extent{1280, 720}; + bool lock_aspect_ratio{true}; + bool decoration{true}; +}; + +struct BorderlessFullscreen {}; + +using DisplayMode = std::variant; + class DesktopApp : public App, public detail::IWsi { public: struct CreateInfo { std::span args{}; CString title{"BaveApp"}; - glm::ivec2 extent{1280, 720}; + DisplayMode mode{Windowed{}}; std::function)> select_gpu{}; - bool lock_aspect_ratio{true}; std::string_view assets_patterns{"assets"}; bool validation_layers{debug_v}; }; @@ -58,6 +67,7 @@ class DesktopApp : public App, public detail::IWsi { void do_shutdown() final; + [[nodiscard]] auto do_get_native_features() const -> FeatureFlags final; [[nodiscard]] auto do_get_window_size() const -> glm::ivec2 final; [[nodiscard]] auto do_get_framebuffer_size() const -> glm::ivec2 final; @@ -72,6 +82,7 @@ class DesktopApp : public App, public detail::IWsi { auto do_set_window_size(glm::ivec2 size) -> bool final; auto do_set_title(CString title) -> bool final; + auto do_set_window_icon(std::span bitmaps) -> bool final; void init_data_store(); void make_window(); diff --git a/lib/include/bave/graphics/render_device.hpp b/lib/include/bave/graphics/render_device.hpp index fad5c3f..0dc6c1e 100644 --- a/lib/include/bave/graphics/render_device.hpp +++ b/lib/include/bave/graphics/render_device.hpp @@ -37,6 +37,8 @@ class RenderDevice { explicit RenderDevice(NotNull wsi, CreateInfo create_info = {}); + [[nodiscard]] auto validation_layers_enabled() const -> bool { return !!m_debug_messenger; } + [[nodiscard]] auto get_instance() const -> vk::Instance { return *m_instance; } [[nodiscard]] auto get_surface() const -> vk::SurfaceKHR { return *m_surface; } [[nodiscard]] auto get_gpu() const -> Gpu const& { return m_gpu; } diff --git a/lib/include/bave/input/mods.hpp b/lib/include/bave/input/mods.hpp index f4d7877..17fb253 100644 --- a/lib/include/bave/input/mods.hpp +++ b/lib/include/bave/input/mods.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace bave { namespace mod { @@ -10,7 +10,7 @@ constexpr size_t alt{3}; constexpr size_t super{4}; constexpr size_t capslock{5}; constexpr size_t numlock{6}; -constexpr size_t count_v{numlock}; +constexpr size_t count_v{numlock + 1}; }; // namespace mod /// @@ -21,8 +21,6 @@ using KeyMods = std::bitset; ///! Create KeyMods with mods set. template ... I> constexpr auto make_key_mods(I const... mods) -> KeyMods { - auto ret = KeyMods{}; - (ret.set(mods), ...); - return ret; + return make_bitset(mods...); } } // namespace bave diff --git a/lib/platform/desktop/desktop_app.cpp b/lib/platform/desktop/desktop_app.cpp index 673ab0a..598db96 100644 --- a/lib/platform/desktop/desktop_app.cpp +++ b/lib/platform/desktop/desktop_app.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -189,6 +190,10 @@ void DesktopApp::render() { void DesktopApp::do_shutdown() { glfwSetWindowShouldClose(m_window.get(), GLFW_TRUE); } +auto DesktopApp::do_get_native_features() const -> FeatureFlags { + return make_bitset(Feature::resizeable, Feature::has_title, Feature::has_icon); +} + auto DesktopApp::do_get_window_size() const -> glm::ivec2 { auto ret = glm::ivec2{}; glfwGetWindowSize(m_window.get(), &ret.x, &ret.y); @@ -244,6 +249,22 @@ auto DesktopApp::do_set_title(CString title) -> bool { return true; } +auto DesktopApp::do_set_window_icon(std::span bitmaps) -> bool { + auto images = std::vector{}; + images.reserve(bitmaps.size()); + for (auto const& bitmap : bitmaps) { + if (bitmap.bytes.empty()) { continue; } + auto image = GLFWimage{ + .width = bitmap.extent.x, + .height = bitmap.extent.y, + .pixels = reinterpret_cast(const_cast(bitmap.bytes.data())), // NOLINT + }; + images.push_back(image); + } + glfwSetWindowIcon(m_window.get(), static_cast(images.size()), images.data()); + return true; +} + auto DesktopApp::self(Ptr window) -> DesktopApp& { auto* ret = static_cast(glfwGetWindowUserPointer(window)); if (ret == nullptr) { throw Error{"Dereferencing null GLFW Window User Pointer"}; } @@ -265,14 +286,33 @@ void DesktopApp::init_data_store() { void DesktopApp::make_window() { if (glfwVulkanSupported() == GLFW_FALSE) { throw Error{"Vulkan not supported"}; } + auto display_mode = m_create_info.mode; + Ptr primary_monitor = glfwGetPrimaryMonitor(); + Ptr video_mode = glfwGetVideoMode(primary_monitor); + if (video_mode == nullptr && std::holds_alternative(display_mode)) { display_mode = Windowed{.extent = {1280, 720}}; } + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - auto* window = glfwCreateWindow(m_create_info.extent.x, m_create_info.extent.y, m_create_info.title.c_str(), nullptr, nullptr); + auto create_window = Visitor{ + [&](BorderlessFullscreen const&) { + glfwWindowHint(GLFW_RED_BITS, video_mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, video_mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, video_mode->blueBits); + glfwWindowHint(GLFW_REFRESH_RATE, video_mode->refreshRate); + return glfwCreateWindow(video_mode->width, video_mode->height, m_create_info.title.c_str(), primary_monitor, nullptr); + }, + [&](Windowed const& w) { + if (!w.decoration) { glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); } + auto* ret = glfwCreateWindow(w.extent.x, w.extent.y, m_create_info.title.c_str(), nullptr, nullptr); + if (w.lock_aspect_ratio) { glfwSetWindowAspectRatio(ret, w.extent.x, w.extent.y); } + return ret; + }, + }; + + auto* window = std::visit(create_window, m_create_info.mode); m_window = std::unique_ptr{window}; if (m_window == nullptr) { throw Error{"Failed to create Window"}; } glfwSetWindowUserPointer(m_window.get(), this); - if (m_create_info.lock_aspect_ratio) { glfwSetWindowAspectRatio(m_window.get(), m_create_info.extent.x, m_create_info.extent.y); } - glfwSetWindowCloseCallback(m_window.get(), [](Ptr window) { self(window).shutdown(); }); glfwSetWindowFocusCallback(m_window.get(), [](Ptr window, int v) { push(window, FocusChange{.in_focus = v == GLFW_TRUE}); }); glfwSetWindowSizeCallback(m_window.get(), [](Ptr window, int x, int y) { push(window, WindowResize{.extent = {x, y}}); }); diff --git a/lib/src/app.cpp b/lib/src/app.cpp index a9b3657..944d88e 100644 --- a/lib/src/app.cpp +++ b/lib/src/app.cpp @@ -64,6 +64,12 @@ auto App::set_framebuffer_size(glm::ivec2 const size) -> bool { return do_set_window_size(w_size); } +auto App::get_features() const -> FeatureFlags { + auto ret = do_get_native_features(); + if (get_render_device().validation_layers_enabled()) { ret.set(Feature::validation_layers); } + return ret; +} + auto App::get_display_ratio() const -> glm::vec2 { auto const w_size = get_window_size(); auto const f_size = get_framebuffer_size(); diff --git a/tools/src/main.cpp b/tools/src/main.cpp index 2254d8e..3a013be 100644 --- a/tools/src/main.cpp +++ b/tools/src/main.cpp @@ -8,8 +8,7 @@ auto main(int argc, char** argv) -> int { auto const daci = bave::DesktopApp::CreateInfo{ .args = bave::make_args(argc, argv), .title = "Bave Tools", - .extent = Applet::window_size_v, - .lock_aspect_ratio = false, + .mode = bave::Windowed{.extent = Applet::window_size_v, .lock_aspect_ratio = false}, .assets_patterns = "assets,example/assets", }; auto app = bave::DesktopApp{daci};