hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-13 19:25:30 +0200
committerhachem <im@hachem.wtf>2025-08-13 19:25:30 +0200
commit1ac0f136629ce4046a5f6529cf3d1e51e96df408 (patch)
treeea42cf71c3a7760d1454f90dca36147d353a3581 /src
parent23086a5d33acc66414f1169bf22abe78b3383f94 (diff)
feat: logging system
Diffstat (limited to 'src')
-rw-r--r--src/core/application.cpp30
-rw-r--r--src/core/application.h6
-rw-r--r--src/core/log.cpp155
-rw-r--r--src/core/log.h154
-rw-r--r--src/core/window.cpp13
-rw-r--r--src/core/window.h1
6 files changed, 339 insertions, 20 deletions
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
{