From 05162c998c049f34c3a9efd771b994ff625afd2f Mon Sep 17 00:00:00 2001 From: Matt Coster Date: Thu, 20 Aug 2020 00:06:35 +0100 Subject: [PATCH] MWE for glfw3.hpp with title.cpp test --- CMakeLists.txt | 11 +++ docs/CMakeLists.txt | 8 +- include/GLFW/glfw3.hpp | 177 +++++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 12 +++ tests/title.cpp | 63 +++++++++++++++ 5 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 include/GLFW/glfw3.hpp create mode 100644 tests/title.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index baeddbfb2..bfd5a1287 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,12 @@ option(GLFW_BUILD_TESTS "Build the GLFW test programs" ${GLFW_STANDALONE}) option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON) option(GLFW_INSTALL "Generate installation target" ON) option(GLFW_VULKAN_STATIC "Assume the Vulkan loader is linked with the application" OFF) +option(GLFW_HPP "Use the glfw3.hpp wrapper for C++" OFF) + +if (GLFW_HPP) + enable_language(CXX) + set(CMAKE_CXX_STANDARD 17) +endif() include(GNUInstallDirs) include(CMakeDependentOption) @@ -290,6 +296,11 @@ if (GLFW_INSTALL) install(DIRECTORY include/GLFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) + if (GLFW_HPP) + install(DIRECTORY include/GLFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN glfw3.hpp) + endif() + install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" "${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake" DESTINATION "${GLFW_CONFIG_PATH}") diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 2347858ec..57fc34fce 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -3,7 +3,13 @@ # (i.e. Pages) list in the generated documentation set(GLFW_DOXYGEN_SOURCES "include/GLFW/glfw3.h" - "include/GLFW/glfw3native.h" + "include/GLFW/glfw3native.h") + +if (GLFW_HPP) + list(APPEND GLFW_DOXYGEN_SOURCES "include/GLFW/glfw3.hpp") +endif() + +list(APPEND GLFW_DOXYGEN_SOURCES "docs/main.dox" "docs/news.dox" "docs/quick.dox" diff --git a/include/GLFW/glfw3.hpp b/include/GLFW/glfw3.hpp new file mode 100644 index 000000000..e0132e325 --- /dev/null +++ b/include/GLFW/glfw3.hpp @@ -0,0 +1,177 @@ +#ifndef _glfw3_hpp_ +#define _glfw3_hpp_ + +#ifndef GLFW_HPP_NAMESPACE +#define GLFW_HPP_NAMESPACE glfw +#endif + +#ifdef GLFW_HPP_NO_STD_STRING +#define GLFW_HPP_STRING char const * +#else +#define GLFW_HPP_STRING std::string +#endif + +#include + +#include +#include +#include +#include +#include + +namespace GLFW_HPP_NAMESPACE { + + namespace _private { +#ifdef GLFW_HPP_NO_STD_STRING + inline GLFW_HPP_STRING makeString_(char const *str) { return str; } + inline char const *cString_(GLFW_HPP_STRING const &str) { return str; } +#else + inline GLFW_HPP_STRING makeString_(char const *str) { return std::string(str); } + inline char const *cString_(GLFW_HPP_STRING const &str) { return str.c_str(); } +#endif + } + + using ErrorFun = GLFWerrorfun; + + struct Size { + int width; + int height; + }; + + enum class ErrorCode { + noError = GLFW_NO_ERROR, + notInitialized = GLFW_NOT_INITIALIZED, + noCurrentContext = GLFW_NO_CURRENT_CONTEXT, + invalidEnum = GLFW_INVALID_ENUM, + invalidValue = GLFW_INVALID_VALUE, + outOfMemory = GLFW_OUT_OF_MEMORY, + apiUnavailable = GLFW_API_UNAVAILABLE, + versionUnavailable = GLFW_VERSION_UNAVAILABLE, + platformError = GLFW_PLATFORM_ERROR, + formatUnavailable = GLFW_FORMAT_UNAVAILABLE, + noWindowContext = GLFW_NO_WINDOW_CONTEXT, + cursorUnavailable = GLFW_CURSOR_UNAVAILABLE, + featureUnavailable = GLFW_FEATURE_UNAVAILABLE, + featureUnimplemented = GLFW_FEATURE_UNIMPLEMENTED, + }; + +} + +namespace std { + template <> + struct is_error_code_enum : public true_type {}; +} + +namespace GLFW_HPP_NAMESPACE { + + class ErrorCategory : public std::error_category { + public: + const char *name() const _NOEXCEPT override { + return nullptr; + } + + std::string message(int __ev) const override { + return std::string(); + } + }; + + inline std::error_code make_error_code(ErrorCode code) { + return {static_cast(code), ErrorCategory()}; + } + + class Error : public std::system_error { + public: + ErrorCode const code; + + private: + Error(ErrorCode const code, GLFW_HPP_STRING const &description) : + std::system_error(std::error_code{code}, description), + code{code} {} + + static std::optional get_() { + char const *description; + auto code = static_cast(glfwGetError(&description)); + + if (code == ErrorCode::noError) { + return std::optional{}; + } + + return Error(code, description ? _private::makeString_(description) : ""); + } + + static void getAndThrow_() { + auto const err = get_(); + if (err) { + throw err.value(); + } + } + + friend class GLFW; + friend class Window; + }; + + class Window { + public: + Window(Size const &size, GLFW_HPP_STRING const &title) : + size_{size}, + title_{title}, + handle_{glfwCreateWindow(size.width, size.height, _private::cString_(title), nullptr, nullptr)} { + Error::getAndThrow_(); + } + + void makeContextCurrent() const { + glfwMakeContextCurrent(this->handle_); + } + + [[nodiscard]] bool shouldClose() const { + return glfwWindowShouldClose(this->handle_); + } + + void swapBuffers() const { + glfwSwapBuffers(this->handle_); + } + + GLFWwindow *handle_; + private: + + Size size_; + GLFW_HPP_STRING title_; + }; + + class GLFW { + public: + GLFW() { + if (!glfwInit()) { + Error::getAndThrow_(); + } + } + + explicit GLFW(ErrorFun errorCallback) : GLFW() { + this->errorCallback = errorCallback; + glfwSetErrorCallback(this->errorCallback); + } + + virtual ~GLFW() { + glfwTerminate(); + } + + Window createWindow(Size const &size, GLFW_HPP_STRING const &title) { + return Window{size, title}; + } + + void swapInterval(int const interval) { + glfwSwapInterval(interval); + } + + void waitEvents() { + glfwWaitEvents(); + } + + private: + ErrorFun errorCallback{}; + }; + +} + + +#endif /* _glfw3_h_ */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 525882449..9fc14fd25 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,6 +41,10 @@ add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD_GL}) add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${GLAD_VULKAN}) add_executable(window WIN32 MACOSX_BUNDLE window.c ${GLAD_GL}) +if (GLFW_HPP) + add_executable(title_cpp WIN32 MACOSX_BUNDLE title.cpp ${GLAD_GL}) +endif() + target_link_libraries(empty Threads::Threads) target_link_libraries(threads Threads::Threads) if (RT_LIBRARY) @@ -53,6 +57,10 @@ set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks tearing threads set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) +if (GLFW_HPP) + list(APPEND GUI_ONLY_BINARIES title_cpp) +endif() + set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES C_STANDARD 99 FOLDER "GLFW3/Tests") @@ -74,6 +82,10 @@ if (APPLE) set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title") set_target_properties(window PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Window") + if (GLFW_HPP) + set_target_properties(title_cpp PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title (C++)") + endif() + set_target_properties(${GUI_ONLY_BINARIES} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION} diff --git a/tests/title.cpp b/tests/title.cpp new file mode 100644 index 000000000..4920c78b1 --- /dev/null +++ b/tests/title.cpp @@ -0,0 +1,63 @@ +//======================================================================== +// UTF-8 window title test (C++ version) +// Copyright (c) Matt Coster +// Based on the original C version by Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test sets a UTF-8 window title +// +//======================================================================== + +#include +#define GLFW_INCLUDE_NONE +#include + +#include +#include + +static void error_callback(int error, const char* description) { + std::cerr << "Error " << error << ": " << description << "\n"; +} + +int main() { + try { + auto glfwInst = glfw::GLFW(&error_callback); + + auto window = glfwInst.createWindow({400, 400}, "English 日本語 русский язык 官話"); + + window.makeContextCurrent(); + gladLoadGL(glfwGetProcAddress); + glfwInst.swapInterval(1); + + while (!window.shouldClose()) { + glClear(GL_COLOR_BUFFER_BIT); + window.swapBuffers(); + glfwInst.waitEvents(); + } + } catch (glfw::Error const &err) { + std::cerr << "GLFW error: " << err.what() << "\n"; + std::exit(EXIT_FAILURE); + } + + return EXIT_SUCCESS; +}