#include "engine.h" #include #include "../lib/glew/GL/glew.h" #include "../lib/glfw/glfw3.h" #include "../lib/glm/glm.hpp" #include "../lib/glm/gtc/matrix_transform.hpp" #include "buffer.h" #include "camera.h" #include "light.h" #include "logger.h" #include "material.h" #include "mesh.h" #include "model.h" #include "shader.h" #include "state.h" #include "texture.h" #include "vertex.h" #include "world.h" // Instance variables std::shared_ptr point_light; // Constants 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) , 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()) { Logger::error("Failed to initialize GLFW"); return; } Logger::info("GLFW initialized successfully"); glfwWindowHint(GLFW_RESIZABLE, false); glfwWindowHint(GLFW_SAMPLES, 8); // Create window window_ = glfwCreateWindow(screen_width_, screen_height_, "Daniel Poveda", nullptr, nullptr); if (window_ == nullptr) { Logger::error("Failed to create OpenGL window"); glfwTerminate(); return; } glfwMakeContextCurrent(window_); // Enable OpenGL features glEnable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); Logger::info( sstr("OpenGL initialized, version: ", reinterpret_cast(glGetString(GL_VERSION)))); // Initialize GLEW glewExperimental = GL_TRUE; GLenum err = glewInit(); if (err != GLEW_OK) { 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/shaders/vertex.glsl", "data/shaders/fragment.glsl"); if (std::strlen(state::default_shader->error()) > 0) { 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(); last_update_time_ = glfwGetTime(); last_frame_time_ = glfwGetTime(); while (is_running()) { const double now = glfwGetTime(); const double delta_time = now - last_update_time_; process_input(delta_time); update(delta_time); 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_->set_ambient(glm::vec3(0.2f, 0.2f, 0.2f)); Logger::info("World created"); // Create camera camera_ = std::make_shared(); camera_->set_position(glm::vec3(0.0f, 4.0f, 12.0f)); camera_->set_rotation(glm::vec3(glm::radians(-20.0f), 0.0f, 0.0f)); camera_->set_projection( glm::perspective(glm::radians(45.0f), static_cast(screen_width_) / static_cast(screen_height_), 0.1f, 100.0f)); 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"); // Load the box_stack model auto box_stack_mesh = Mesh::load("data/models/box_stack.obj"); if (box_stack_mesh) { auto box_stack_model = std::make_shared(box_stack_mesh); box_stack_model->set_position(glm::vec3(-2.0f, -1.25f, 0.0f)); models_.push_back(box_stack_model); world_->add_entity(box_stack_model); Logger::info("Box stack model loaded and added to world"); } // Load the gunslinger model auto gunslinger_mesh = Mesh::load("data/models/gunslinger.obj"); if (gunslinger_mesh) { auto gunslinger_model = std::make_shared(gunslinger_mesh); gunslinger_model->set_position(glm::vec3(2.0f, 0.0f, 0.0f)); gunslinger_model->set_rotation( glm::vec3(0.0f, glm::radians(-30.0f), 0.0f)); gunslinger_model->set_scale(glm::vec3(0.1f, 0.1f, 0.1f)); models_.push_back(gunslinger_model); world_->add_entity(gunslinger_model); Logger::info("Gunslinger model loaded and added to world"); } // Create directional light auto directional_light = std::make_shared(); directional_light->set_type(Light::Type::DIRECTIONAL); directional_light->set_color(glm::vec3(1.0f, 1.0f, 1.0f)); directional_light->set_intensity(1.0f); directional_light->set_position(glm::normalize( glm::vec3(1.0f, 1.0f, 1.0f))); // Use position as direction world_->add_entity(directional_light); Logger::info("Directional light created and added to world"); // Create point light point_light = std::make_shared(); point_light->set_type(Light::Type::POINT); point_light->set_color(glm::vec3(1.0f, 0.0f, 0.0f)); point_light->set_intensity(2.0f); point_light->set_linear_attenuation(0.2f); point_light->set_position(glm::vec3(5.0f, 0.0f, 0.0f)); world_->add_entity(point_light); Logger::info("Point light created and added to world"); Logger::info("Scene setup complete"); } void Engine::start() { // Called once after setup, before the main loop // Can be used for initialization that needs the scene to be ready } void Engine::process_input(const double delta_time) { glfwPollEvents(); if (!camera_) { return; } constexpr float camera_speed = 7.5f; glm::vec3 forward = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 right = glm::vec3(1.0f, 0.0f, 0.0f); glm::mat4 rotation = glm::mat4(1.0f); rotation = glm::rotate(rotation, camera_->rotation().y, glm::vec3(0.0f, 1.0f, 0.0f)); rotation = glm::rotate(rotation, camera_->rotation().x, glm::vec3(1.0f, 0.0f, 0.0f)); forward = glm::vec3(rotation * glm::vec4(forward, 0.0f)); right = glm::vec3(rotation * glm::vec4(right, 0.0f)); const float movement = camera_speed * static_cast(delta_time); if (glfwGetKey(window_, GLFW_KEY_UP) == GLFW_PRESS) { camera_->set_position(camera_->position() + forward * movement); } if (glfwGetKey(window_, GLFW_KEY_DOWN) == GLFW_PRESS) { camera_->set_position(camera_->position() - forward * movement); } if (glfwGetKey(window_, GLFW_KEY_LEFT) == GLFW_PRESS) { camera_->set_position(camera_->position() - right * movement); } if (glfwGetKey(window_, GLFW_KEY_RIGHT) == GLFW_PRESS) { camera_->set_position(camera_->position() + right * movement); } } void Engine::update(const double delta_time) { // Update angle for orbiting light angle_ += delta_time; // Make point light orbit around the model if (point_light) { constexpr float radius = 7.5f; point_light->set_position(glm::vec3(radius * cos(angle_), 2.0f, radius * sin(angle_))); } // Update world world_->update(static_cast(delta_time)); } void Engine::render() { // Draw world world_->draw(); // Swap buffers glfwSwapBuffers(window_); } bool Engine::is_running() const { return window_ && !glfwWindowShouldClose(window_) && !glfwGetKey(window_, GLFW_KEY_ESCAPE); }