284 lines
7.4 KiB
C++
284 lines
7.4 KiB
C++
#include "engine.h"
|
|
|
|
#include <vector>
|
|
|
|
#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<Light> 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<const char*>(glGetString(GL_VERSION))));
|
|
|
|
// Initialize GLEW
|
|
glewExperimental = GL_TRUE;
|
|
GLenum err = glewInit();
|
|
if (err != GLEW_OK) {
|
|
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/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>();
|
|
world_->set_ambient(glm::vec3(0.2f, 0.2f, 0.2f));
|
|
Logger::info("World created");
|
|
|
|
// Create camera
|
|
camera_ = std::make_shared<Camera>();
|
|
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<float>(screen_width_)
|
|
/ static_cast<float>(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<Model>(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<Model>(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<Light>();
|
|
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<Light>();
|
|
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<float>(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<float>(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);
|
|
}
|