feat: add logger class
This commit is contained in:
		| @@ -1,11 +1,11 @@ | ||||
| #include "buffer.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <iostream> | ||||
|  | ||||
| #include "../lib/glew/GL/glew.h" | ||||
| #include "../lib/glfw/glfw3.h" | ||||
|  | ||||
| #include "logger.h" | ||||
| #include "vertex.h" | ||||
|  | ||||
| Buffer::Buffer(const std::vector<Vertex>&   vertices, | ||||
| @@ -30,6 +30,9 @@ Buffer::Buffer(const std::vector<Vertex>&   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 | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| #include "engine.h" | ||||
|  | ||||
| #include <iostream> | ||||
| #include <vector> | ||||
|  | ||||
| #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<const char*>(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<const char*>(glewGetErrorString(err)))); | ||||
| 		glfwTerminate(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// Initialize default shader | ||||
| 	Logger::info("Loading default shaders..."); | ||||
| 	state::default_shader = | ||||
| 	    std::make_shared<Shader>("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<World>(); | ||||
| 	Logger::info("World created"); | ||||
|  | ||||
| 	// Create camera | ||||
| 	camera_ = std::make_shared<Camera>(); | ||||
| @@ -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<Vertex> vertices = { | ||||
| @@ -141,6 +163,8 @@ void Engine::setup() | ||||
| 	auto buffer = std::make_shared<Buffer>(vertices, indices); | ||||
| 	mesh_	    = std::make_shared<Mesh>(); | ||||
| 	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() | ||||
|   | ||||
							
								
								
									
										57
									
								
								src/logger.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/logger.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| #include "logger.h" | ||||
|  | ||||
| #include <chrono> | ||||
| #include <iostream> | ||||
|  | ||||
| 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); | ||||
| } | ||||
							
								
								
									
										48
									
								
								src/logger.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/logger.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| #ifndef LOGGER_H_ | ||||
| #define LOGGER_H_ | ||||
|  | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| // Utility: Concatenate any types into a string | ||||
| template <typename... Args> | ||||
| 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<LogEntry>& messages() | ||||
| 	{ | ||||
| 		return messages_; | ||||
| 	} | ||||
| 	static void clear() { messages_.clear(); } | ||||
|  | ||||
| private: | ||||
| 	inline static std::vector<LogEntry> messages_{}; | ||||
| }; | ||||
|  | ||||
| #endif // LOGGER_H_ | ||||
| @@ -1,13 +1,13 @@ | ||||
| #include "shader.h" | ||||
|  | ||||
| #include <vector> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| #include <iostream> | ||||
| #include <vector> | ||||
|  | ||||
| #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; | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,11 @@ | ||||
| #include "world.h" | ||||
| #include "entity.h" | ||||
| #include "camera.h" | ||||
|  | ||||
| #include <algorithm> | ||||
|  | ||||
| #include "camera.h" | ||||
| #include "entity.h" | ||||
| #include "logger.h" | ||||
|  | ||||
| void World::add_entity(const std::shared_ptr<Entity>& entity) | ||||
| { | ||||
| 	entities_.push_back(entity); | ||||
| @@ -12,6 +15,11 @@ void World::add_entity(const std::shared_ptr<Entity>& entity) | ||||
| 	    std::dynamic_pointer_cast<Camera>(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>& 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>& entity) | ||||
| 		    std::find(cameras_.begin(), cameras_.end(), camera); | ||||
| 		if (camIt != cameras_.end()) { | ||||
| 			cameras_.erase(camIt); | ||||
| 			Logger::info("Camera removed from world"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user