#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// static VkBool32 vk_debug_callback (VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) { (void)flags; (void)objType; (void)obj; (void)location; (void)code; (void)layerPrefix; (void)msg; (void)userData; std::cerr << "validation: " << msg << '\n'; return VK_FALSE; } /////////////////////////////////////////////////////////////////////////////// struct vertex_t { util::point2f position; util::srgba3f colour; }; //----------------------------------------------------------------------------- static constexpr vertex_t VERTICES[] = { { { 0.0f, -0.5f }, { 1.0f, 0.0f, 0.0f } }, { { 0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f } }, { {-0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f } }, }; namespace glfw { namespace detail { constexpr const char* error_string (int code) noexcept; } struct error : public std::exception { public: static void try_code (int code); static void throw_code [[noreturn]] (int code); static void throw_code [[noreturn]] (void); static void push (int code) { s_current = code; } private: static std::atomic s_current; }; template struct error_code : public error { virtual ~error_code () = default; static constexpr const char *message = detail::error_string (CodeV); }; } std::atomic glfw::error::s_current; void glfw_error_callback (int code ,const char *description) { LOG_WARN ("glfw: %s", description); glfw::error::push (code); } namespace glfw { class instance { public: instance () { if (std::lock_guard l {s_count.guard}; !s_count.value++) glfwInit (); glfwSetErrorCallback (glfw_error_callback); static constexpr struct { int tag; int val; } HINTS[] { { GLFW_CLIENT_API, GLFW_NO_API }, { GLFW_RESIZABLE, GLFW_FALSE }, }; for (const auto [tag,val]: HINTS) glfwWindowHint (tag, val); } std::vector required_extensions (void) const { unsigned count; auto values = glfwGetRequiredInstanceExtensions (&count); return { values + 0, values + count }; } void poll_events (void) { glfwPollEvents (); } ~instance () { if (std::lock_guard l {s_count.guard}; !--s_count.value) glfwTerminate (); } private: // TODO: value doesnt' need to be atomic, but it's not performance // critical, and I'm not particularly familiar with c++ memory // ordering primitives. so it's probably safer this way for now. static struct count_t { std::mutex guard; std::atomic value; } s_count; }; class window { public: using native_t = GLFWwindow*; window (util::extent2i resolution, const char *name): m_native (glfwCreateWindow (resolution.w, resolution.h, name, nullptr, nullptr)) { if (!m_native) error::throw_code (); } native_t native (void) const { return m_native; } bool should_close (void) const { return glfwWindowShouldClose (native ()); } private: native_t m_native; }; }; /////////////////////////////////////////////////////////////////////////////// template struct to_format; #define TO_FORMAT(S,T,VALUE) \ template