From 41c9b68eb93de2a88d1be8b0e225ef36126e80d8 Mon Sep 17 00:00:00 2001 From: Daniel Poveda Date: Mon, 13 Oct 2025 17:30:05 +0200 Subject: [PATCH] feat: add logger class --- src/buffer.cpp | 6 ++++- src/engine.cpp | 56 +++++++++++++++++++++++++++++----------- src/logger.cpp | 57 +++++++++++++++++++++++++++++++++++++++++ src/logger.h | 48 ++++++++++++++++++++++++++++++++++ src/shader.cpp | 18 ++++++++++--- src/world.cpp | 14 ++++++++-- ugine3d.vcxproj | 2 ++ ugine3d.vcxproj.filters | 6 +++++ 8 files changed, 185 insertions(+), 22 deletions(-) create mode 100644 src/logger.cpp create mode 100644 src/logger.h diff --git a/src/buffer.cpp b/src/buffer.cpp index d84f1c7..fad961a 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -1,11 +1,11 @@ #include "buffer.h" #include -#include #include "../lib/glew/GL/glew.h" #include "../lib/glfw/glfw3.h" +#include "logger.h" #include "vertex.h" Buffer::Buffer(const std::vector& vertices, @@ -30,6 +30,9 @@ Buffer::Buffer(const std::vector& vertices, glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr); glEnableVertexAttribArray(0); + + Logger::info(sstr("Buffer created with ", vertices.size(), + " vertices and ", indices.size(), " indices")); } Buffer::~Buffer() @@ -37,6 +40,7 @@ Buffer::~Buffer() glDeleteVertexArrays(1, &vao_); glDeleteBuffers(1, &vbo_); glDeleteBuffers(1, &ebo_); + Logger::info("Buffer destroyed"); } void Buffer::draw(const Shader& shader) const diff --git a/src/engine.cpp b/src/engine.cpp index 3a2a9d0..782c161 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,6 +1,5 @@ #include "engine.h" -#include #include #include "../lib/glew/GL/glew.h" @@ -10,6 +9,7 @@ #include "buffer.h" #include "camera.h" +#include "logger.h" #include "mesh.h" #include "model.h" #include "shader.h" @@ -17,32 +17,37 @@ #include "vertex.h" #include "world.h" -constexpr int SCREEN_WIDTH = 800; -constexpr int SCREEN_HEIGHT = 600; -constexpr double FPS_LIMIT = 1.0 / 60.0; +constexpr int screen_width = 800; +constexpr int screen_height = 600; +constexpr double fps_limit = 1.0 / 60.0; Engine::Engine() : window_(nullptr) - , screen_width_(SCREEN_WIDTH) - , screen_height_(SCREEN_HEIGHT) + , screen_width_(screen_width) + , screen_height_(screen_height) , last_update_time_(0.0) , last_frame_time_(0.0) , angle_(0.0) { + Logger::info("Engine created"); } Engine::~Engine() { + Logger::info("Engine destroyed"); destroy(); } void Engine::initialize() { + Logger::info("Initializing engine..."); + // Initialize GLFW if (!glfwInit()) { - std::cerr << "Failed to initialize GLFW\n"; + Logger::error("Failed to initialize GLFW"); return; } + Logger::info("GLFW initialized successfully"); glfwWindowHint(GLFW_RESIZABLE, false); glfwWindowHint(GLFW_SAMPLES, 8); @@ -51,7 +56,7 @@ void Engine::initialize() window_ = glfwCreateWindow(screen_width_, screen_height_, "Daniel Poveda", nullptr, nullptr); if (window_ == nullptr) { - std::cerr << "Failed to create OpenGL window\n"; + Logger::error("Failed to create OpenGL window"); glfwTerminate(); return; } @@ -61,30 +66,39 @@ void Engine::initialize() glEnable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); - std::cout << "OpenGL initialized, version: " << glGetString(GL_VERSION) - << "\n"; + Logger::info( + sstr("OpenGL initialized, version: ", + reinterpret_cast(glGetString(GL_VERSION)))); // Initialize GLEW glewExperimental = GL_TRUE; GLenum err = glewInit(); if (err != GLEW_OK) { - std::cerr << "Failed to initialize GLEW: " - << glewGetErrorString(err) << "\n"; + Logger::error(sstr( + "Failed to initialize GLEW: ", + reinterpret_cast(glewGetErrorString(err)))); glfwTerminate(); return; } // Initialize default shader + Logger::info("Loading default shaders..."); state::default_shader = std::make_shared("data/vertex.glsl", "data/fragment.glsl"); if (std::strlen(state::default_shader->error()) > 0) { - std::cerr << "Failed to initialize shaders: " - << state::default_shader->error() << "\n"; + Logger::error(sstr("Failed to initialize shaders: ", + state::default_shader->error())); + } else { + Logger::info("Default shaders loaded successfully"); } + + Logger::info("Engine initialization complete"); } void Engine::run() { + Logger::info("Starting game loop..."); + setup(); start(); @@ -98,26 +112,33 @@ void Engine::run() process_input(); update(delta_time); - if (now - last_frame_time_ >= FPS_LIMIT) { + if (now - last_frame_time_ >= fps_limit) { render(); last_frame_time_ = now; } last_update_time_ = now; } + + Logger::info("Game loop ended"); } void Engine::destroy() { if (window_) { + Logger::info("Shutting down engine..."); glfwTerminate(); window_ = nullptr; + Logger::info("Engine shutdown complete"); } } void Engine::setup() { + Logger::info("Setting up scene..."); + // Create world world_ = std::make_unique(); + Logger::info("World created"); // Create camera camera_ = std::make_shared(); @@ -130,6 +151,7 @@ void Engine::setup() camera_->set_viewport(glm::ivec4(0, 0, screen_width_, screen_height_)); camera_->set_clear_color(glm::vec3(0.1f, 0.1f, 0.1f)); world_->add_entity(camera_); + Logger::info("Camera created and added to world"); // Create triangle mesh std::vector vertices = { @@ -141,6 +163,8 @@ void Engine::setup() auto buffer = std::make_shared(vertices, indices); mesh_ = std::make_shared(); mesh_->add_buffer(buffer); + Logger::info(sstr("Mesh created with ", vertices.size(), + " vertices and ", indices.size(), " indices")); // Create 9 models in a 3x3 grid for (int row = 0; row < 3; ++row) { @@ -153,6 +177,8 @@ void Engine::setup() world_->add_entity(model); } } + Logger::info(sstr("Created ", models_.size(), " models in scene")); + Logger::info("Scene setup complete"); } void Engine::start() diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..4e63dbd --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,57 @@ +#include "logger.h" + +#include +#include + +namespace { + +std::string current_datetime_string() +{ + auto now = std::chrono::system_clock::now(); + auto now_time_t = std::chrono::system_clock::to_time_t(now); + struct tm now_tm {}; +#ifdef _WIN32 + localtime_s(&now_tm, &now_time_t); +#else + localtime_r(&now_time_t, &now_tm); +#endif + + char buffer[30]; + std::strftime(buffer, sizeof(buffer) / sizeof(char), "%Y-%m-%d %H:%M:%S", + &now_tm); + return std::string{buffer}; +} + +} // namespace + +void Logger::info(const std::string& message) +{ + LogEntry entry; + entry.type = LogType::info; + entry.message = + "[" + current_datetime_string() + "] [INFO]: " + message; + + std::cout << "\x1B[32m" << entry.message << "\033[0m" << std::endl; + messages_.push_back(entry); +} + +void Logger::warn(const std::string& message) +{ + LogEntry entry; + entry.type = LogType::warn; + entry.message = + "[" + current_datetime_string() + "] [WARN]: " + message; + + std::cout << "\x1B[93m" << entry.message << "\033[0m" << std::endl; + messages_.push_back(entry); +} + +void Logger::error(const std::string& message) +{ + LogEntry entry; + entry.type = LogType::error; + entry.message = "[" + current_datetime_string() + "] [ERROR]: " + message; + + std::cerr << "\x1B[91m" << entry.message << "\033[0m" << std::endl; + messages_.push_back(entry); +} diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..58ba0bd --- /dev/null +++ b/src/logger.h @@ -0,0 +1,48 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include +#include +#include + +// Utility: Concatenate any types into a string +template +std::string sstr(Args&&... args) +{ + std::ostringstream stream; + stream << std::dec; + ((stream << args), ...); + return stream.str(); +} + +// Log types +enum class LogType { + info = 0, + warn, + error +}; + +// Log entry structure +struct LogEntry { + LogType type{LogType::info}; + std::string message{}; +}; + +// Logger class +class Logger { +public: + static void info(const std::string& message); + static void warn(const std::string& message); + static void error(const std::string& message); + + [[nodiscard]] static const std::vector& messages() + { + return messages_; + } + static void clear() { messages_.clear(); } + +private: + inline static std::vector messages_{}; +}; + +#endif // LOGGER_H_ diff --git a/src/shader.cpp b/src/shader.cpp index a761d5d..2345660 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,13 +1,13 @@ #include "shader.h" -#include #include #include -#include +#include #include "../lib/glew/GL/glew.h" #include "../lib/glfw/glfw3.h" +#include "logger.h" #include "vertex.h" Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) @@ -106,7 +106,8 @@ std::string Shader::read_shader_file(const std::string& filename) { std::ifstream file(filename); if (!file) { - error_ = "Failed to open shader file: " + filename + "\n"; + error_ = "Failed to open shader file: " + filename; + Logger::error(sstr("Failed to open shader file: ", filename)); return std::string{0}; } @@ -117,11 +118,16 @@ std::string Shader::read_shader_file(const std::string& filename) uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path) { + const char* shader_type_name = + (type == GL_VERTEX_SHADER) ? "vertex" : "fragment"; + std::string source = read_shader_file(source_path); - // std::cout << "SHADER FILE: " << source << "\n"; if (source.empty()) return 0; + Logger::info( + sstr("Compiling ", shader_type_name, " shader: ", source_path)); + const uint32_t shader = glCreateShader(type); const char* shader_code = source.c_str(); @@ -135,9 +141,13 @@ uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path) char buffer[1024]; glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer); error_ = buffer; + Logger::error( + sstr("Shader compilation failed (", shader_type_name, "): ", + buffer)); glDeleteShader(shader); return 0; } + Logger::info(sstr(shader_type_name, " shader compiled successfully")); return shader; } diff --git a/src/world.cpp b/src/world.cpp index ef2e610..a21816c 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,8 +1,11 @@ #include "world.h" -#include "entity.h" -#include "camera.h" + #include +#include "camera.h" +#include "entity.h" +#include "logger.h" + void World::add_entity(const std::shared_ptr& entity) { entities_.push_back(entity); @@ -12,6 +15,11 @@ void World::add_entity(const std::shared_ptr& entity) std::dynamic_pointer_cast(entity); if (camera) { cameras_.push_back(camera); + Logger::info(sstr("Camera added to world (total cameras: ", + cameras_.size(), ")")); + } else { + Logger::info(sstr("Entity added to world (total entities: ", + entities_.size(), ")")); } } @@ -21,6 +29,7 @@ void World::remove_entity(const std::shared_ptr& entity) auto it = std::find(entities_.begin(), entities_.end(), entity); if (it != entities_.end()) { entities_.erase(it); + Logger::info("Entity removed from world"); } // Check if entity is a camera and remove from cameras list @@ -31,6 +40,7 @@ void World::remove_entity(const std::shared_ptr& entity) std::find(cameras_.begin(), cameras_.end(), camera); if (camIt != cameras_.end()) { cameras_.erase(camIt); + Logger::info("Camera removed from world"); } } } diff --git a/ugine3d.vcxproj b/ugine3d.vcxproj index 702a68d..d0f602b 100644 --- a/ugine3d.vcxproj +++ b/ugine3d.vcxproj @@ -163,6 +163,7 @@ + @@ -176,6 +177,7 @@ + diff --git a/ugine3d.vcxproj.filters b/ugine3d.vcxproj.filters index 39837d9..9da0674 100644 --- a/ugine3d.vcxproj.filters +++ b/ugine3d.vcxproj.filters @@ -63,6 +63,9 @@ Source Files + + Source Files + @@ -98,6 +101,9 @@ Source Files + + Source Files +