diff options
| author | hachem <im@hachem.wtf> | 2025-08-13 19:25:30 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-08-13 19:25:30 +0200 |
| commit | 1ac0f136629ce4046a5f6529cf3d1e51e96df408 (patch) | |
| tree | ea42cf71c3a7760d1454f90dca36147d353a3581 | |
| parent | 23086a5d33acc66414f1169bf22abe78b3383f94 (diff) | |
feat: logging system
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | premake5.lua | 22 | ||||
| -rw-r--r-- | src/core/application.cpp | 30 | ||||
| -rw-r--r-- | src/core/application.h | 6 | ||||
| -rw-r--r-- | src/core/log.cpp | 155 | ||||
| -rw-r--r-- | src/core/log.h | 154 | ||||
| -rw-r--r-- | src/core/window.cpp | 13 | ||||
| -rw-r--r-- | src/core/window.h | 1 |
8 files changed, 357 insertions, 27 deletions
@@ -1,3 +1,6 @@ +logs/ +*.log + bin/ bin-int/ diff --git a/premake5.lua b/premake5.lua index b97a436..6f31afe 100644 --- a/premake5.lua +++ b/premake5.lua @@ -14,7 +14,14 @@ workspace "Donut" "MultiProcessorCompile" } -outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}" + filter "system:windows" + defines "DONUT_WINDOWS" + filter "system:linux" + defines "DONUT_LINUX" + filter "system:macosx" + defines "DONUT_MACOS" + +outputdir = "%{cfg.buildcfg}-%{cfg.system}/%{prj.name}" IncludeDir = {} IncludeDir["glfw"] = "ext/glfw/include" @@ -27,8 +34,8 @@ project "GLAD" kind "StaticLib" language "C" staticruntime "on" - targetdir ("bin/" .. outputdir .. "/%{prj.name}") - objdir ("bin-int/" .. outputdir .. "/%{prj.name}") + targetdir ("bin/" .. outputdir) + objdir ("bin-int/" .. outputdir) files { @@ -60,8 +67,8 @@ project "GLFW" staticruntime "on" warnings "off" - targetdir ("bin/" .. outputdir .. "/%{prj.name}") - objdir ("bin-int/" .. outputdir .. "/%{prj.name}") + targetdir ("bin/" .. outputdir) + objdir ("bin-int/" .. outputdir) files { @@ -201,10 +208,11 @@ group "" project "Donut" kind "ConsoleApp" language "C++" + cppdialect "C++17" staticruntime "on" - targetdir ("bin/" .. outputdir .. "/%{prj.name}") - objdir ("bin-int/" .. outputdir .. "/%{prj.name}") + targetdir ("bin/" .. outputdir) + objdir ("bin-int/" .. outputdir) defines { diff --git a/src/core/application.cpp b/src/core/application.cpp index 435b6aa..c4c0e71 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -22,6 +22,7 @@ namespace Donut s_instance = this; m_window = std::make_unique<Window>(name, width, height); + m_window->set_event_callback([this](Event& event) { on_event(event); @@ -68,9 +69,13 @@ namespace Donut dispatcher.dispatch<WindowResizeEvent>([this, &event](WindowResizeEvent& e) { if (e.get_width() == 0 || e.get_height() == 0) + { m_minimized = true; + } else + { m_minimized = false; + } Renderer::on_window_resize(e.get_width(), e.get_height()); @@ -152,7 +157,9 @@ namespace Donut void Application::on_init() { + Logger::init(); Renderer::init(); + Renderer::on_window_resize(1280, 720); RenderCommand::set_face_culling(false); @@ -228,30 +235,23 @@ namespace Donut if (!m_compute_shader) { - std::cout << "Failed to create compute shader! Falling back to CPU texture generation." << std::endl; + DONUT_WARN("Failed to create compute shader! Falling back to CPU texture generation."); m_use_compute_shader = false; } else - std::cout << "Compute shader created successfully!" << std::endl; + DONUT_INFO("Compute shader created successfully!"); m_processed_texture = Texture2D::create(256, 256); m_compute_brightness = 0.0f; m_compute_contrast = 1.0f; m_compute_saturation = 1.0f; m_use_compute_shader = true; - - std::cout << "=== Compute Shader Test ===" << std::endl; - std::cout << "C - Toggle compute shader on/off" << std::endl; - std::cout << "Arrow Keys - Adjust brightness (Up/Down) and contrast (Left/Right)" << std::endl; - std::cout << "Q/E - Adjust saturation" << std::endl; - std::cout << "WASD - Move camera" << std::endl; - std::cout << "Mouse - Look around" << std::endl; - std::cout << "==========================" << std::endl; } void Application::on_shutdown() { Renderer::shutdown(); + Logger::shutdown(); } void Application::on_update() @@ -280,7 +280,7 @@ namespace Donut if (m_keys[GLFW_KEY_C] && !c_key_pressed) { m_use_compute_shader = !m_use_compute_shader; - std::cout << "Compute shader: " << (m_use_compute_shader ? "ON" : "OFF") << std::endl; + DONUT_INFO("Compute shader: {}", (m_use_compute_shader ? "ON" : "OFF")); c_key_pressed = true; } if (!m_keys[GLFW_KEY_C]) @@ -306,9 +306,8 @@ namespace Donut status_timer += m_delta_time; if (status_timer > 2.0f) { - std::cout << "Compute Shader Status - Brightness: " << m_compute_brightness - << ", Contrast: " << m_compute_contrast - << ", Saturation: " << m_compute_saturation << std::endl; + DONUT_INFO("Compute Shader Status:\nBrightness: {}\nContrast: {}\nSaturation: {}", + m_compute_brightness, m_compute_contrast, m_compute_saturation); status_timer = 0.0f; } @@ -320,7 +319,8 @@ namespace Donut Renderer::set_clear_color({ 0.0f, 0.0f, 0.0f, 1.0f }); Renderer::clear(); - if (m_use_compute_shader && m_processed_texture) + if (m_use_compute_shader && + m_processed_texture) { m_processed_texture->bind(0); m_shader->set_int("u_Texture", 0); diff --git a/src/core/application.h b/src/core/application.h index e5a983a..fe04ff7 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -1,10 +1,12 @@ #pragma once +#include <memory> +#include <functional> + #include "window.h" #include "event.h" #include "camera.h" -#include <memory> -#include <functional> +#include "log.h" #include "rendering/vertex_array.h" #include "rendering/vertex_buffer.h" diff --git a/src/core/log.cpp b/src/core/log.cpp new file mode 100644 index 0000000..ec031a5 --- /dev/null +++ b/src/core/log.cpp @@ -0,0 +1,155 @@ +#include "log.h" +#include <filesystem> + +#if defined(DONUT_WINDOWS) + #include <windows.h> +#endif + +namespace Donut +{ + std::shared_ptr<Logger> Logger::s_logger; + + void Logger::init() + { + s_logger = std::make_shared<Logger>(); + s_logger->set_log_level(LogLevel::Info); + s_logger->enable_console_output(true); + s_logger->enable_file_output(true); + s_logger->set_log_file("logs/donut.log"); + + s_logger->log_message(LogLevel::Info, "Logging system initialized"); + } + + void Logger::shutdown() + { + if (s_logger) + s_logger->log_message(LogLevel::Info, "Shutting down logging system"); + s_logger.reset(); + } + + std::shared_ptr<Logger> Logger::get_logger() + { + return s_logger; + } + + Logger::Logger() + : m_log_level(LogLevel::Info), + m_console_output(true), + m_file_output(false) { } + + Logger::~Logger() + { + if (m_log_file.is_open()) + m_log_file.close(); + } + + void Logger::set_log_file(const std::string& filename) + { + std::filesystem::path log_path(filename); + std::filesystem::create_directories(log_path.parent_path()); + + m_log_file.open(filename, std::ios::app); + if (!m_log_file.is_open()) + std::cerr << "Failed to open log file: " << filename << std::endl; + } + + std::string Logger::get_time_stamp() + { + auto now = std::chrono::system_clock::now(); + auto time_t = std::chrono::system_clock::to_time_t(now); + + std::stringstream ss; + ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S"); + + return ss.str(); + } + + std::string Logger::get_log_level_string(LogLevel level) + { + switch (level) + { + case LogLevel::trace: return "TRACE"; + case LogLevel::Info: return "INFO"; + case LogLevel::Warn: return "WARN"; + case LogLevel::Err: return "ERROR"; + case LogLevel::Fatal: return "FATAL"; + default: return "UNKNOWN"; + } + } + + void Logger::set_console_color(LogLevel level) + { +#if defined(DONUT_WINDOWS) + HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); + WORD color; + + switch (level) { + case LogLevel::trace: + color = FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + case LogLevel::Info: + color = FOREGROUND_GREEN | + FOREGROUND_INTENSITY; + break; + case LogLevel::Warn: + color = FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_INTENSITY; + break; + case LogLevel::Err: + color = FOREGROUND_RED | + FOREGROUND_INTENSITY; + break; + case LogLevel::Fatal: + color = FOREGROUND_RED | + FOREGROUND_BLUE | + FOREGROUND_INTENSITY; + break; + default: + color = FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + } + + SetConsoleTextAttribute(h_console, color); +#else + const char* color_code; + switch (level) { + case LogLevel::trace: + color_code = "\033[37m"; + break; + case LogLevel::Info: + color_code = "\033[32;1m"; + break; + case LogLevel::Warn: + color_code = "\033[33;1m"; + break; + case LogLevel::Err: + color_code = "\033[31;1m"; + break; + case LogLevel::Fatal: + color_code = "\033[35;1m"; + break; + default: + color_code = "\033[37m"; + break; + } + std::cout << color_code; +#endif + } + + void Logger::reset_console_color() + { +#if defined(DONUT_WINDOWS) + HANDLE h_console = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(h_console, FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE); +#else + std::cout << "\033[0m"; +#endif + } +} diff --git a/src/core/log.h b/src/core/log.h new file mode 100644 index 0000000..77324f5 --- /dev/null +++ b/src/core/log.h @@ -0,0 +1,154 @@ +#pragma once + +#include <string> +#include <memory> +#include <vector> +#include <sstream> +#include <iostream> +#include <fstream> +#include <chrono> +#include <iomanip> +#include <mutex> +#include <string_view> + +namespace Donut +{ + enum class LogLevel + { + trace = 0, + Info = 2, + Warn = 3, + Err = 4, + Fatal = 5 + }; + + class Logger + { + public: + static void init(); + static void shutdown(); + + static std::shared_ptr<Logger> get_logger(); + + template<typename... Args> + static void trace(const std::string_view& format, const Args&... args) + { + auto logger = get_logger(); + if (logger) logger->log_message(LogLevel::trace, format, args...); + } + + template<typename... Args> + static void info(const std::string_view& format, const Args&... args) + { + auto logger = get_logger(); + if (logger) logger->log_message(LogLevel::Info, format, args...); + } + + template<typename... Args> + static void warn(const std::string_view& format, const Args&... args) + { + auto logger = get_logger(); + if (logger) logger->log_message(LogLevel::Warn, format, args...); + } + + template<typename... Args> + static void error(const std::string_view& format, const Args&... args) + { + auto logger = get_logger(); + if (logger) logger->log_message(LogLevel::Err, format, args...); + } + + template<typename... Args> + static void fatal(const std::string_view& format, const Args&... args) + { + auto logger = get_logger(); + if (logger) logger->log_message(LogLevel::Fatal, format, args...); + } + + template<typename... Args> + void log_message(LogLevel level, const std::string_view& format, const Args&... args) + { + if (level < m_log_level) + return; + + std::lock_guard<std::mutex> lock(m_mutex); + std::string message = format_string(format, args...); + std::string full_message = get_time_stamp() + " [" + get_log_level_string(level) + "] " + message; + + if (m_console_output) + { + set_console_color(level); + std::cout << full_message << std::endl; + reset_console_color(); + } + + if (m_file_output && m_log_file.is_open()) + { + m_log_file << full_message << std::endl; + m_log_file.flush(); + } + } + + template<typename... Args> + std::string format_string(const std::string_view& format, const Args&... args) + { + std::string result = format.data(); + std::vector<std::string> arg_strings = { to_string(args)... }; + + size_t arg_index = 0; + size_t pos = 0; + + while ((pos = result.find("{}", pos)) != std::string::npos && arg_index < arg_strings.size()) + { + result.replace(pos, 2, arg_strings[arg_index]); + pos += arg_strings[arg_index].length(); + arg_index++; + } + + return result; + } + + template<typename T> + std::string to_string(const T& value) + { + std::stringstream ss; + ss << value; + return ss.str(); + } + + void set_log_level(LogLevel level) { m_log_level = level; } + void enable_console_output(bool enable) { m_console_output = enable; } + void enable_file_output(bool enable) { m_file_output = enable; } + void set_log_file(const std::string& filename); + public: + Logger(); + ~Logger(); + + std::string get_time_stamp(); + std::string get_log_level_string(LogLevel level); + void set_console_color(LogLevel level); + void reset_console_color(); + private: + LogLevel m_log_level; + bool m_console_output; + bool m_file_output; + std::ofstream m_log_file; + std::mutex m_mutex; + + static std::shared_ptr<Logger> s_logger; + }; +} + +#if defined(DONUT_DEBUG) + #define DONUT_TRACE(format, ...) ::Donut::Logger::trace(format, ##__VA_ARGS__) + #define DONUT_INFO(format, ...) ::Donut::Logger::info(format, ##__VA_ARGS__) + #define DONUT_WARN(format, ...) ::Donut::Logger::warn(format, ##__VA_ARGS__) + #define DONUT_ERROR(format, ...) ::Donut::Logger::error(format, ##__VA_ARGS__) + #define DONUT_FATAL(format, ...) ::Donut::Logger::fatal(format, ##__VA_ARGS__) +#else + #define DONUT_TRACE(format, ...) {} + #define DONUT_INFO(format, ...) {} + #define DONUT_WARN(format, ...) {} + #define DONUT_ERROR(format, ...) {} + #define DONUT_FATAL(format, ...) {} +#endif diff --git a/src/core/window.cpp b/src/core/window.cpp index 9605f8c..a32dddb 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -21,25 +21,30 @@ namespace Donut void Window::init() { + DONUT_INFO("Initializing window: ", m_title, " (", m_width, "x", m_height, ")"); + if (!s_glfw_initialized) { int success = glfwInit(); if (!success) { - std::cout << "Could not initialize GLFW!" << std::endl; + DONUT_ERROR("Could not initialize GLFW!"); return; } s_glfw_initialized = true; + DONUT_INFO("GLFW initialized successfully"); } m_window = glfwCreateWindow(m_width, m_height, m_title.c_str(), nullptr, nullptr); if (!m_window) { - std::cout << "Could not create GLFW window!" << std::endl; + DONUT_ERROR("Could not create GLFW window!"); glfwTerminate(); return; } + + DONUT_INFO("GLFW window created successfully"); glfwMakeContextCurrent(m_window); glfwSetWindowUserPointer(m_window, this); @@ -60,6 +65,7 @@ namespace Donut void Window::shutdown() { + DONUT_INFO("Shutting down window: ", m_title); glfwDestroyWindow(m_window); s_glfw_window_count--; @@ -67,6 +73,7 @@ namespace Donut { glfwTerminate(); s_glfw_initialized = false; + DONUT_INFO("GLFW terminated (no more windows)"); } } @@ -97,7 +104,7 @@ namespace Donut void Window::glfw_error_callback(int error, const char* description) { - std::cout << "GLFW Error (" << error << "): " << description << std::endl; + DONUT_ERROR("GLFW Error (", error, "): ", description); } void Window::glfw_window_close_callback(GLFWwindow* window) diff --git a/src/core/window.h b/src/core/window.h index cf80cac..ae79b6d 100644 --- a/src/core/window.h +++ b/src/core/window.h @@ -3,6 +3,7 @@ #include <GLFW/glfw3.h> #include <string> #include "event.h" +#include "log.h" namespace Donut { |
