diff --git a/src/engine.cpp b/src/engine.cpp new file mode 100644 index 0000000..93593b0 --- /dev/null +++ b/src/engine.cpp @@ -0,0 +1,197 @@ +#include "engine.h" + +#include +#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 "mesh.h" +#include "model.h" +#include "shader.h" +#include "state.h" +#include "vertex.h" +#include "world.h" + +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) +{ +} + +Engine::~Engine() +{ + destroy(); +} + +void Engine::initialize() +{ + // Initialize GLFW + if (!glfwInit()) { + std::cerr << "Failed to initialize GLFW\n"; + return; + } + + glfwWindowHint(GLFW_RESIZABLE, false); + glfwWindowHint(GLFW_SAMPLES, 8); + + // Create window + window_ = glfwCreateWindow(screen_width_, screen_height_, + "Daniel Poveda", nullptr, nullptr); + if (window_ == nullptr) { + std::cerr << "Failed to create OpenGL window\n"; + glfwTerminate(); + return; + } + glfwMakeContextCurrent(window_); + + // Enable OpenGL features + glEnable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + + std::cout << "OpenGL initialized, version: " << glGetString(GL_VERSION) + << "\n"; + + // Initialize GLEW + glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if (err != GLEW_OK) { + std::cerr << "Failed to initialize GLEW: " + << glewGetErrorString(err) << "\n"; + glfwTerminate(); + return; + } + + // Initialize default shader + 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"; + } +} + +void Engine::run() +{ + 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(); + update(delta_time); + + if (now - last_frame_time_ >= FPS_LIMIT) { + render(); + last_frame_time_ = now; + } + last_update_time_ = now; + } +} + +void Engine::destroy() +{ + if (window_) { + glfwTerminate(); + window_ = nullptr; + } +} + +void Engine::setup() +{ + // Create world + world_ = std::make_unique(); + + // Create camera + camera_ = std::make_shared(); + camera_->set_position(glm::vec3(0.0f, 0.0f, 6.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_); + + // Create triangle mesh + std::vector vertices = { + {{0.0f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}}, + {{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}}, + {{0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}}; + std::vector indices = {0, 1, 2}; + + auto buffer = std::make_shared(vertices, indices); + mesh_ = std::make_shared(); + mesh_->add_buffer(buffer); + + // Create 9 models in a 3x3 grid + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + auto model = std::make_shared(mesh_); + model->set_position( + glm::vec3(-3.0f + static_cast(col) * 3.0f, + 0.0f, static_cast(-row) * 3.0f)); + models_.push_back(model); + world_->add_entity(model); + } + } +} + +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() +{ + glfwPollEvents(); +} + +void Engine::update(const double delta_time) +{ + // Update angle for rotation + angle_ += 32.0 * delta_time; + + // Update rotation for all models + for (auto& model : models_) { + model->set_rotation(glm::vec3( + 0.0f, glm::radians(static_cast(angle_)), 0.0f)); + } + + // 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); +} diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 0000000..59f07a7 --- /dev/null +++ b/src/engine.h @@ -0,0 +1,50 @@ +#ifndef ENGINE_H_ +#define ENGINE_H_ + +#include +#include + +#include "../lib/glfw/glfw3.h" + +class World; +class Camera; +class Model; +class Mesh; + +class Engine { +public: + Engine(); + ~Engine(); + + void initialize(); + void run(); + void destroy(); + +private: + // Lifecycle methods + void setup(); + void start(); + void process_input(); + void update(const double delta_time); + void render(); + + [[nodiscard]] bool is_running() const; + + // Window and OpenGL + GLFWwindow* window_; + int screen_width_; + int screen_height_; + + // Game objects + std::unique_ptr world_; + std::shared_ptr camera_; + std::vector> models_; + std::shared_ptr mesh_; + + // Game loop timing + double last_update_time_; + double last_frame_time_; + double angle_; +}; + +#endif // ENGINE_H_ diff --git a/src/entity.h b/src/entity.h index e5471bd..05e212e 100644 --- a/src/entity.h +++ b/src/entity.h @@ -37,7 +37,7 @@ public: void move(const glm::vec3& vec); - virtual void update(float delta_time) + virtual void update(const float delta_time) { // ... } diff --git a/src/main.cpp b/src/main.cpp index 6e06698..c706756 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,144 +2,15 @@ #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") #endif*/ -#include -#include -#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 "vertex.h" -#include "shader.h" -#include "buffer.h" -#include "state.h" -#include "mesh.h" -#include "entity.h" -#include "model.h" -#include "camera.h" -#include "world.h" - -#define SCREEN_WIDTH 800 -#define SCREEN_HEIGHT 600 +#include "engine.h" int main() { - // Initialize OpenGL - if (!glfwInit()) { - std::cerr << "Failed to initialize glfw\n"; - return 1; - } + Engine engine; - glfwWindowHint(GLFW_RESIZABLE, false); - glfwWindowHint(GLFW_SAMPLES, 8); - - // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - // glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - GLFWwindow* win = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, - "Daniel Poveda", nullptr, nullptr); - if (win == nullptr) { - std::cerr << "Failed to create opengl window\n"; - glfwTerminate(); - return 1; - } - glfwMakeContextCurrent(win); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_SCISSOR_TEST); - - std::cout << "OpenGL initialized, version: " << glGetString(GL_VERSION) - << "\n"; - - // Initialize GLEW - glewExperimental = GL_TRUE; - GLenum err = glewInit(); - if (err != GLEW_OK) { - std::cerr << "Failed to initialize GLEW: " - << glewGetErrorString(err) << "\n"; - glfwTerminate(); - return 1; - } - - // Initialize default shader - 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"; - } - - // Create world - World world; - - // Create camera - auto camera = std::make_shared(); - camera->set_position(glm::vec3(0.0f, 0.0f, 6.0f)); - camera->set_projection(glm::perspective( - glm::radians(45.0f), - static_cast(SCREEN_WIDTH) / 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); - - // Create triangle mesh - std::vector vertices = { - {{0.0f, 0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}}, - {{-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}}, - {{0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}}; - std::vector indices = {0, 1, 2}; - - auto buffer = std::make_shared(vertices, indices); - auto mesh = std::make_shared(); - mesh->add_buffer(buffer); - - // Create 9 models in a 3x3 grid - std::vector> models; - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 3; ++col) { - auto model = std::make_shared(mesh); - model->set_position( - glm::vec3(-3.0f + static_cast(col) * 3.0f, - 0.0f, static_cast(-row) * 3.0f)); - models.push_back(model); - world.add_entity(model); - } - } - - // Main loop - double angle = 0.0; - double lastTime = glfwGetTime(); - while (!glfwWindowShouldClose(win) - && !glfwGetKey(win, GLFW_KEY_ESCAPE)) { - // Delta time - double currentTime = glfwGetTime(); - double deltaTime = currentTime - lastTime; - lastTime = currentTime; - - // Update angle - angle += 32.0 * deltaTime; - - // Update rotation for all models - for (auto& model : models) { - model->set_rotation(glm::vec3( - 0.0f, glm::radians(static_cast(angle)), - 0.0f)); - } - - // Update and draw world - world.update(static_cast(deltaTime)); - world.draw(); - - // Refresh screen - glfwSwapBuffers(win); - glfwPollEvents(); - } - - // Shutdown - glfwTerminate(); + engine.initialize(); + engine.run(); + engine.destroy(); return 0; } diff --git a/ugine3d.vcxproj b/ugine3d.vcxproj index c2a6669..6021d72 100644 --- a/ugine3d.vcxproj +++ b/ugine3d.vcxproj @@ -161,6 +161,7 @@ + @@ -173,6 +174,7 @@ + diff --git a/ugine3d.vcxproj.filters b/ugine3d.vcxproj.filters index cf0192f..290bd8b 100644 --- a/ugine3d.vcxproj.filters +++ b/ugine3d.vcxproj.filters @@ -60,6 +60,9 @@ Source Files + + Source Files + @@ -95,6 +98,9 @@ Source Files + + Source Files +