diff --git a/.codecov.yml b/.codecov.yml index df786ef..8ca5442 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -14,6 +14,7 @@ comment: ignore: - "**/*-test.cpp" # ignore test harness code + - "**/utility" - "**/detail" - "flux-config" - "flux-meta" \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5269350..349e83d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ if(FLUX_ENABLE_COVERAGE) message(STATUS "Code coverage: ON") else() - message(ERROR "Code coverage for compiler ${CMAKE_CXX_COMPILER_ID} is unsupported") + message(FATAL_ERROR "Code coverage is not supported by the ${CMAKE_CXX_COMPILER_ID} compiler.") endif() endif() @@ -27,6 +27,7 @@ endif() #----------------------------------------------------------------------------------------------------------------------- add_subdirectory("flux-config") +add_subdirectory("flux-foundation") add_subdirectory("flux-io") add_subdirectory("flux-meta") diff --git a/flux-foundation/CMakeLists.txt b/flux-foundation/CMakeLists.txt new file mode 100644 index 0000000..456a631 --- /dev/null +++ b/flux-foundation/CMakeLists.txt @@ -0,0 +1,8 @@ +flux_static_library(foundation + COMMON + SOURCE + "flux/foundation/dummy.cpp" + LINK + flux::io) + +# code: language="CMake" insertSpaces=true tabSize=4 \ No newline at end of file diff --git a/flux-foundation/flux/foundation.hpp b/flux-foundation/flux/foundation.hpp new file mode 100644 index 0000000..780002c --- /dev/null +++ b/flux-foundation/flux/foundation.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include \ No newline at end of file diff --git a/flux-foundation/flux/foundation/dummy.cpp b/flux-foundation/flux/foundation/dummy.cpp new file mode 100644 index 0000000..e69de29 diff --git a/flux-foundation/flux/foundation/utility.hpp b/flux-foundation/flux/foundation/utility.hpp new file mode 100644 index 0000000..2a78735 --- /dev/null +++ b/flux-foundation/flux/foundation/utility.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/addressof.hpp b/flux-foundation/flux/foundation/utility/addressof.hpp new file mode 100644 index 0000000..fef1040 --- /dev/null +++ b/flux-foundation/flux/foundation/utility/addressof.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace flux::fou { + +// clang-format off +template +#if __has_cpp_attribute(clang::always_inline) +[[clang::always_inline]] +#endif +[[nodiscard]] inline constexpr T* addressof(T& arg) noexcept { + return __builtin_addressof(arg); +} + +template +T const* addressof(T const&&) = delete; +// clang-format on + +} // namespace flux::fou \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/detail/logger_impl.hpp b/flux-foundation/flux/foundation/utility/detail/logger_impl.hpp new file mode 100644 index 0000000..058874b --- /dev/null +++ b/flux-foundation/flux/foundation/utility/detail/logger_impl.hpp @@ -0,0 +1,219 @@ +// NOTE: +// This header is such a mess, it will need to be revisited in the future and probably refactored. +// Maybe add multithreading support as well. But at this stage, let it be as it is. +// TODO: +// Revisit it. +#pragma once + +#include +#include + +#include +#include + +namespace fast_io { + +struct flux_source_location_scatter { + basic_io_scatter_t file_name; + basic_io_scatter_t function_name; + std::uint_least32_t line; + std::uint_least32_t column; +}; + +namespace details { + +inline constexpr std::size_t +print_reserve_size_source_location_impl(flux_source_location_scatter location) noexcept { + constexpr auto reserve_size = print_reserve_size(io_reserve_type); + constexpr auto total_size = (reserve_size * 2 + 3); + return intrinsics::add_or_overflow_die_chain(location.file_name.len, location.function_name.len, + total_size); +} + +inline constexpr char* +print_reserve_define_source_location_impl(char* it, + flux_source_location_scatter location) noexcept { + constexpr auto io_reserve = io_reserve_type; + *(it = non_overlapped_copy_n(location.file_name.base, location.file_name.len, it)) = ':'; + *(it = print_reserve_define(io_reserve, ++it, location.line)) = ':'; + *(it = print_reserve_define(io_reserve, ++it, location.column)) = ':'; + return non_overlapped_copy_n(location.function_name.base, location.function_name.len, ++it); +} + +inline constexpr flux_source_location_scatter +print_alias_define_source_location_impl(flux::fou::source_location location) noexcept { + using flux::fou::detail::strip_path; + return {{strip_path(location.file_name()), cstr_len(strip_path(location.file_name()))}, + {location.function_name(), cstr_len(location.function_name())}, + location.line(), + location.column()}; +} + +} // namespace details + +inline constexpr std::size_t +print_reserve_size(io_reserve_type_t, + flux_source_location_scatter location) noexcept { + return details::print_reserve_size_source_location_impl(location); +} + +inline constexpr char* print_reserve_define(io_reserve_type_t, + char* iter, + flux_source_location_scatter location) noexcept { + return details::print_reserve_define_source_location_impl(iter, location); +} + +inline constexpr flux_source_location_scatter +print_alias_define(io_alias_t, flux::fou::source_location location) noexcept { + return details::print_alias_define_source_location_impl(location); +} + +namespace manipulators { +inline constexpr auto +cur_src_loc(flux::fou::source_location location = flux::fou::source_location::current()) noexcept { + return location; +} +} // namespace manipulators +} // namespace fast_io + +namespace flux::fou { + +struct [[nodiscard]] to_file final {}; +struct [[nodiscard]] to_console final {}; + +struct [[nodiscard]] ansi_color final { + std::uint8_t r = 255; + std::uint8_t g = 255; + std::uint8_t b = 255; + std::uint8_t a = 255; // << Unused, exists only for alignment. + + struct [[nodiscard]] escape_code final { + static constexpr std::string_view begin() noexcept { + return "\033[38;2;"; + } + static constexpr std::string_view end() noexcept { + return "\033[0;00m"; + } + }; +}; + +constexpr auto print_reserve_size(fast_io::io_reserve_type_t) noexcept { + using namespace fast_io; + constexpr auto reserve_size = print_reserve_size(io_reserve_type); + constexpr auto total_size = reserve_size * 3; + return total_size; +} + +constexpr auto print_reserve_define(fast_io::io_reserve_type_t, char* it, + ansi_color color) noexcept { + using namespace fast_io; + // clang-format off + *(it = print_reserve_define(io_reserve_type, it, color.r)) = ';'; + *(it = print_reserve_define(io_reserve_type, ++it, color.g)) = ';'; + *(it = print_reserve_define(io_reserve_type, ++it, color.b)) = 'm'; + // clang-format on + return ++it; +} +static_assert(fast_io::reserve_printable); + +template +constexpr void println(ansi_color color, T&& device, Args&&... args) noexcept { + io::println(std::forward(device), ansi_color::escape_code::begin(), color, + std::forward(args)..., ansi_color::escape_code::end()); +} + +namespace detail { + +// clang-format off +template +struct [[maybe_unused]] dummy_logger; +// clang-format on + +} // namespace detail + +// clang-format off +template +detail::dummy_logger& logger() noexcept; +// clang-format on + +namespace detail { + +inline auto get_local_time() noexcept { + [[maybe_unused]] static bool once = ([] { fast_io::posix_tzset(); }(), true); + return local(fast_io::posix_clock_gettime(fast_io::posix_clock_id::realtime)); +} + +#define FLUX_PRINT_LOGGER_HEADER_TO(output_file) \ + io::println(output_file, left("+", 36, '-'), left("+", 63, '-'), left("+", 13, '-'), \ + left("+", 32, '-')); \ + io::println(output_file, "| ", left("Date / Time", 33), " | ", left("Location", 60), " | ", \ + left("Level", 10), " | Message"); \ + io::println(output_file, left("+", 36, '-'), left("+", 63, '-'), left("+", 13, '-'), \ + left("+", 32, '-')); + +// clang-format off +template <> +struct [[maybe_unused]] dummy_logger final { + constexpr dummy_logger(dummy_logger const&) = delete; + constexpr dummy_logger(dummy_logger&&) = delete; + constexpr dummy_logger& operator=(dummy_logger const&) = delete; + constexpr dummy_logger& operator=(dummy_logger&&) = delete; + + template + constexpr void log(ansi_color color, std::string_view prefix, meta::tuple tuple, + source_location location) noexcept { + using namespace io; + [[maybe_unused]] io_flush_guard guard{output_file_}; + meta::apply( + [&](auto&&... args) { + println(color, output_file_, " ", left(get_local_time(), 36), + left(location, 63), left(prefix, 13), std::forward(args)...); + }, + tuple); + } + + template + friend dummy_logger& flux::fou::logger() noexcept; + +private: + constexpr dummy_logger() noexcept : output_file_{"log.ansi", io::open_mode::app} { + using namespace io; + FLUX_PRINT_LOGGER_HEADER_TO(output_file_) + } + constexpr ~dummy_logger() = default; + + io::obuf_file output_file_; +}; + +template <> +struct [[maybe_unused]] dummy_logger final { + constexpr dummy_logger(dummy_logger const&) = delete; + constexpr dummy_logger(dummy_logger&&) = delete; + constexpr dummy_logger& operator=(dummy_logger const&) = delete; + constexpr dummy_logger& operator=(dummy_logger&&) = delete; + + template + constexpr void log(ansi_color color, std::string_view prefix, meta::tuple tuple, + source_location location) noexcept { + using namespace io; + meta::apply( + [&](auto&&... args) noexcept { + println(color, out(), left(get_local_time(), 34), location, " ", prefix, " ", + std::forward(args)...); + }, + tuple); + } + + template + friend dummy_logger& flux::fou::logger() noexcept; + +private: + constexpr dummy_logger() noexcept = default; + constexpr ~dummy_logger() = default; +}; +// clang-format on + +#undef FLUX_PRINT_LOGGER_HEADER_TO + +} // namespace detail +} // namespace flux::fou \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/detail/strip_path.hpp b/flux-foundation/flux/foundation/utility/detail/strip_path.hpp new file mode 100644 index 0000000..ca3686c --- /dev/null +++ b/flux-foundation/flux/foundation/utility/detail/strip_path.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace flux::fou::detail { + +constexpr bool is_path_sep(char c) noexcept { + return c == '/' || c == '\\'; +} + +constexpr char const* strip_path(char const* path) noexcept { + auto last_name = path; + for (auto p = path; *p; ++p) { + if (is_path_sep(*p) && *(p + 1)) + last_name = p + 1; + } + return last_name; +} + +constexpr char const* last_dot_of(char const* p) noexcept { + char const* last_dot = nullptr; + for (; *p; ++p) { + if (*p == '.') + last_dot = p; + } + return last_dot ? last_dot : p; +} + +} // namespace flux::fou::detail \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/launder.hpp b/flux-foundation/flux/foundation/utility/launder.hpp new file mode 100644 index 0000000..f436a94 --- /dev/null +++ b/flux-foundation/flux/foundation/utility/launder.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace flux::fou { + +// clang-format off +template +#if __has_cpp_attribute(clang::always_inline) +[[clang::always_inline]] +#endif +[[nodiscard]] inline constexpr T* launder(T* p) noexcept { + return __builtin_launder(p); +} +// clang-format on + +} // namespace flux::fou \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/logger.hpp b/flux-foundation/flux/foundation/utility/logger.hpp new file mode 100644 index 0000000..88b7401 --- /dev/null +++ b/flux-foundation/flux/foundation/utility/logger.hpp @@ -0,0 +1,174 @@ +#pragma once +#include + +#include +#include + +namespace flux::fou { + +namespace out { + +inline constexpr to_file file = {}; +inline constexpr to_console console = {}; + +} // namespace out + +namespace color { + +// clang-format off +inline constexpr ansi_color cyan = {0 , 200, 240, 255}; +inline constexpr ansi_color white = {255, 255, 255, 255}; +inline constexpr ansi_color yellow = {231, 231, 31 , 255}; +inline constexpr ansi_color red = {231, 31 , 31 , 255}; +// clang-format on + +} // namespace color + +// clang-format off +template +detail::dummy_logger& logger() noexcept { + static detail::dummy_logger instance; + return instance; +} +// clang-format on + +// clang-format off +template struct [[maybe_unused]] trace final { + // Explicitly writes the trace log to the console. + constexpr explicit trace( + [[maybe_unused]] to_console output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::cyan, "[TRACE]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Explicitly writes the trace log to the file. + constexpr explicit trace( + [[maybe_unused]] to_file output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::cyan, "[TRACE]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Writes the trace log to the console by default. + constexpr explicit trace( + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept + : trace(out::console, std::forward(args)..., location) {} +}; + +template struct [[maybe_unused]] debug final { + // Explicitly writes the debug log to the console. + constexpr explicit debug( + [[maybe_unused]] to_console output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::white, "[DEBUG]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Explicitly writes the debug log to the file. + constexpr explicit debug( + [[maybe_unused]] to_file output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::white, "[DEBUG]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Writes the debug log to the console by default. + constexpr explicit debug( + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept + : debug(out::console, std::forward(args)..., location) {} +}; + +template struct [[maybe_unused]] warning final { + // Explicitly writes the warning log to the console. + constexpr explicit warning( + [[maybe_unused]] to_console output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::yellow, "[WARNING]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Explicitly writes the warning log to the file. + constexpr explicit warning( + [[maybe_unused]] to_file output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::yellow, "[WARNING]", std::forward_as_tuple(std::move(args)...), + location); + } + + // Writes the warning log to the console by default. + constexpr explicit warning( + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept + : warning(out::console, std::forward(args)..., location) {} +}; + +template struct [[maybe_unused]] error final { + // Explicitly writes the error log to the console. + constexpr explicit error( + [[maybe_unused]] to_console output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::red, "[ERROR]", std::forward_as_tuple(std::move(args)...), + location); + fast_terminate(); + } + + // Explicitly writes the error log to the file. + constexpr explicit error( + [[maybe_unused]] to_file output, + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept { + logger().log(color::red, "[ERROR]", std::forward_as_tuple(std::move(args)...), + location); + fast_terminate(); + } + + // Writes the error log to the console by default. + constexpr explicit error( + [[maybe_unused]] Args&&... args, + [[maybe_unused]] source_location location = source_location::current()) noexcept + : error(out::console, std::forward(args)..., location) {} +}; +// clang-format on + +// clang-format off +template trace (to_console, Args&&...) -> trace ; +template debug (to_console, Args&&...) -> debug ; +template warning(to_console, Args&&...) -> warning; +template error (to_console, Args&&...) -> error ; + +template trace (to_file, Args&&...) -> trace ; +template debug (to_file, Args&&...) -> debug ; +template warning(to_file, Args&&...) -> warning; +template error (to_file, Args&&...) -> error ; + +template trace (Args&&...) -> trace ; +template debug (Args&&...) -> debug ; +template warning(Args&&...) -> warning; +template error (Args&&...) -> error ; +// clang-format on + +} // namespace flux::fou + +namespace flux::log { + +namespace out { +using flux::fou::out::console; +using flux::fou::out::file; +} // namespace out + +using flux::fou::debug; +using flux::fou::error; +using flux::fou::trace; +using flux::fou::warning; + +} // namespace flux::log \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/source_location.hpp b/flux-foundation/flux/foundation/utility/source_location.hpp new file mode 100644 index 0000000..a72c352 --- /dev/null +++ b/flux-foundation/flux/foundation/utility/source_location.hpp @@ -0,0 +1,46 @@ +#pragma once +#include + +namespace flux::fou { + +struct [[nodiscard]] source_location final { + static consteval source_location + current(std::uint_least32_t line = __builtin_LINE(), + std::uint_least32_t column = __builtin_COLUMN(), + char const* file_name = __builtin_FILE(), + char const* function_name = __builtin_FUNCTION()) noexcept { + source_location source{}; + source.line_ = line; + source.column_ = column; + source.file_name_ = file_name; + source.function_name_ = function_name; + + return source; + } + + constexpr source_location() noexcept = default; + + constexpr std::uint_least32_t line() const noexcept { + return line_; + } + + constexpr std::uint_least32_t column() const noexcept { + return column_; + } + + constexpr char const* file_name() const noexcept { + return file_name_; + } + + constexpr char const* function_name() const noexcept { + return function_name_; + } + +private: + std::uint_least32_t line_ = {}; + std::uint_least32_t column_ = {}; + char const* file_name_ = ""; + char const* function_name_ = ""; +}; + +} // namespace flux::fou \ No newline at end of file diff --git a/flux-foundation/flux/foundation/utility/terminate.hpp b/flux-foundation/flux/foundation/utility/terminate.hpp new file mode 100644 index 0000000..331013f --- /dev/null +++ b/flux-foundation/flux/foundation/utility/terminate.hpp @@ -0,0 +1,19 @@ +#pragma once +#if defined(_MSC_VER) && !defined(FLUX_CLANG) +# include +#endif + +namespace flux::fou { + +[[noreturn]] inline void fast_terminate() noexcept { +// @see: https://llvm.org/doxygen/Compiler_8h_source.html +#if __has_builtin(__builtin_trap) + __builtin_trap(); +#elif __has_builtin(__builtin_abort) + __builtin_abort(); +#else + std::abort(); +#endif +} + +} // namespace flux::fou diff --git a/flux-foundation/flux/foundation/utility/unreachable.hpp b/flux-foundation/flux/foundation/utility/unreachable.hpp new file mode 100644 index 0000000..1dc7b21 --- /dev/null +++ b/flux-foundation/flux/foundation/utility/unreachable.hpp @@ -0,0 +1,16 @@ +#pragma once +#if defined(_MSC_VER) && !defined(FLUX_CLANG) +# include +#endif + +namespace flux::fou { + +[[noreturn]] inline void unreachable() noexcept { +#if __has_builtin(__builtin_unreachable) + __builtin_unreachable(); +#else + __assume(false); +#endif +} + +} // namespace flux::fou diff --git a/flux-meta/flux/meta.hpp b/flux-meta/flux/meta.hpp index a4064e6..6d3df02 100644 --- a/flux-meta/flux/meta.hpp +++ b/flux-meta/flux/meta.hpp @@ -8,9 +8,10 @@ #include #include #include -#include -#include +// clang-format on + #include #include +#include #include -// clang-format on \ No newline at end of file +#include \ No newline at end of file diff --git a/flux-playground/CMakeLists.txt b/flux-playground/CMakeLists.txt index b0c7cde..9abc5e2 100644 --- a/flux-playground/CMakeLists.txt +++ b/flux-playground/CMakeLists.txt @@ -8,6 +8,7 @@ flux_executable(playground glfw::glfw glad::glad imgui::imgui + flux::foundation WINDOWS SOURCE "playground.cpp" diff --git a/flux-playground/playground.cpp b/flux-playground/playground.cpp index 1e59f12..58161ad 100644 --- a/flux-playground/playground.cpp +++ b/flux-playground/playground.cpp @@ -7,22 +7,59 @@ // GLFW (include after glad) #include -#include -#include +// FLUX +#include + +// clang-format off +#if __has_cpp_attribute(gnu::dllimport) && !defined(__WINE__) +[[gnu::dllimport]] +#endif +#if __has_cpp_attribute(gnu::stdcall) && !defined(__WINE__) +[[gnu::stdcall]] +#endif +extern void* GetStdHandle(std::uint_least32_t) noexcept +#if defined(FLUX_CLANG) +__asm__("GetStdHandle") +#endif +; + +#if __has_cpp_attribute(gnu::dllimport) && !defined(__WINE__) +[[gnu::dllimport]] +#endif +#if __has_cpp_attribute(gnu::stdcall) && !defined(__WINE__) +[[gnu::stdcall]] +#endif +extern int SetConsoleMode(void*, std::uint_least32_t) noexcept +#if defined(FLUX_CLANG) +__asm__("SetConsoleMode") +#endif +; + +#if __has_cpp_attribute(gnu::dllimport) && !defined(__WINE__) +[[gnu::dllimport]] +#endif +#if __has_cpp_attribute(gnu::stdcall) && !defined(__WINE__) +[[gnu::stdcall]] +#endif +extern int GetConsoleMode(void*, std::uint_least32_t*) noexcept +#if defined(FLUX_CLANG) +__asm__("GetConsoleMode") +#endif +; +// clang-format on // Window dimensions -const GLuint WIDTH = 400, HEIGHT = 300; +GLuint const WIDTH = 400, HEIGHT = 300; -GLFWwindow* create_window(const char* name, int major, int minor) { - std::cout << "Creating Window, OpenGL " << major << "." << minor << ": " << name << std::endl; +GLFWwindow* create_window(char const* name, int major, int minor) { + flux::log::debug("Creating Window, OpenGL ", major, ".", minor, ": ", flux::io::c_str(name)); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); - GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, name, NULL, NULL); - return window; + return glfwCreateWindow(WIDTH, HEIGHT, name, NULL, NULL); } GladGLContext* create_context(GLFWwindow* window) { @@ -34,8 +71,8 @@ GladGLContext* create_context(GLFWwindow* window) { return nullptr; int version = gladLoadGLContext(context, glfwGetProcAddress); - std::cout << "Loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." - << GLAD_VERSION_MINOR(version) << std::endl; + flux::log::trace("Loaded OpenGL ", GLAD_VERSION_MAJOR(version), ".", + GLAD_VERSION_MINOR(version)); return context; } @@ -62,15 +99,25 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod } int main() { + constexpr auto std_output_handle = static_cast(-11); + constexpr auto enable_processed_output = static_cast(0x0001); + constexpr auto enable_virtual_terminal_processing = static_cast(0x0004); + + auto* handle = GetStdHandle(std_output_handle); + std::uint_least32_t console_mode = 0; + GetConsoleMode(handle, &console_mode); + console_mode |= enable_processed_output; + console_mode |= enable_virtual_terminal_processing; + SetConsoleMode(handle, console_mode); + glfwInit(); - GLFWwindow* window1 = create_window("Window 1", 3, 3); - GLFWwindow* window2 = create_window("Window 2", 3, 2); + GLFWwindow* window1 = create_window("Window 1", 4, 6); + GLFWwindow* window2 = create_window("Window 2", 4, 5); if (!window1 || !window2) { - std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); - return -1; + flux::log::error("Failed to create GLFW window"); } glfwSetKeyCallback(window1, key_callback); @@ -80,9 +127,9 @@ int main() { GladGLContext* context2 = create_context(window2); if (!context1 || !context2) { - std::cout << "Failed to initialize GL contexts" << std::endl; free_context(context1); free_context(context2); + flux::log::error("Failed to initialize GL contexts"); } glfwMakeContextCurrent(window1);