feat: engine class

This commit is contained in:
2025-10-13 16:51:07 +02:00
parent f1a24f576b
commit 4e2c62aaf4
6 changed files with 261 additions and 135 deletions

197
src/engine.cpp Normal file
View File

@@ -0,0 +1,197 @@
#include "engine.h"
#include <iostream>
#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 "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<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";
}
}
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<World>();
// Create camera
camera_ = std::make_shared<Camera>();
camera_->set_position(glm::vec3(0.0f, 0.0f, 6.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_);
// Create triangle mesh
std::vector<Vertex> 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<uint16_t> indices = {0, 1, 2};
auto buffer = std::make_shared<Buffer>(vertices, indices);
mesh_ = std::make_shared<Mesh>();
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<Model>(mesh_);
model->set_position(
glm::vec3(-3.0f + static_cast<float>(col) * 3.0f,
0.0f, static_cast<float>(-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<float>(angle_)), 0.0f));
}
// 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);
}

50
src/engine.h Normal file
View File

@@ -0,0 +1,50 @@
#ifndef ENGINE_H_
#define ENGINE_H_
#include <memory>
#include <vector>
#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> world_;
std::shared_ptr<Camera> camera_;
std::vector<std::shared_ptr<Model>> models_;
std::shared_ptr<Mesh> mesh_;
// Game loop timing
double last_update_time_;
double last_frame_time_;
double angle_;
};
#endif // ENGINE_H_

View File

@@ -37,7 +37,7 @@ public:
void move(const glm::vec3& vec); void move(const glm::vec3& vec);
virtual void update(float delta_time) virtual void update(const float delta_time)
{ {
// ... // ...
} }

View File

@@ -2,144 +2,15 @@
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#endif*/ #endif*/
#include <iostream> #include "engine.h"
#include <vector>
#include <memory>
#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
int main() int main()
{ {
// Initialize OpenGL Engine engine;
if (!glfwInit()) {
std::cerr << "Failed to initialize glfw\n";
return 1;
}
glfwWindowHint(GLFW_RESIZABLE, false); engine.initialize();
glfwWindowHint(GLFW_SAMPLES, 8); engine.run();
engine.destroy();
// 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<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";
}
// Create world
World world;
// Create camera
auto camera = std::make_shared<Camera>();
camera->set_position(glm::vec3(0.0f, 0.0f, 6.0f));
camera->set_projection(glm::perspective(
glm::radians(45.0f),
static_cast<float>(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<Vertex> 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<uint16_t> indices = {0, 1, 2};
auto buffer = std::make_shared<Buffer>(vertices, indices);
auto mesh = std::make_shared<Mesh>();
mesh->add_buffer(buffer);
// Create 9 models in a 3x3 grid
std::vector<std::shared_ptr<Model>> models;
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
auto model = std::make_shared<Model>(mesh);
model->set_position(
glm::vec3(-3.0f + static_cast<float>(col) * 3.0f,
0.0f, static_cast<float>(-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<float>(angle)),
0.0f));
}
// Update and draw world
world.update(static_cast<float>(deltaTime));
world.draw();
// Refresh screen
glfwSwapBuffers(win);
glfwPollEvents();
}
// Shutdown
glfwTerminate();
return 0; return 0;
} }

View File

@@ -161,6 +161,7 @@
<ClInclude Include="lib\glfw\glfw3native.h" /> <ClInclude Include="lib\glfw\glfw3native.h" />
<ClInclude Include="src\buffer.h" /> <ClInclude Include="src\buffer.h" />
<ClInclude Include="src\camera.h" /> <ClInclude Include="src\camera.h" />
<ClInclude Include="src\engine.h" />
<ClInclude Include="src\entity.h" /> <ClInclude Include="src\entity.h" />
<ClInclude Include="src\mesh.h" /> <ClInclude Include="src\mesh.h" />
<ClInclude Include="src\model.h" /> <ClInclude Include="src\model.h" />
@@ -173,6 +174,7 @@
<ClCompile Include="lib\glew\glew.c" /> <ClCompile Include="lib\glew\glew.c" />
<ClCompile Include="src\buffer.cpp" /> <ClCompile Include="src\buffer.cpp" />
<ClCompile Include="src\camera.cpp" /> <ClCompile Include="src\camera.cpp" />
<ClCompile Include="src\engine.cpp" />
<ClCompile Include="src\entity.cpp" /> <ClCompile Include="src\entity.cpp" />
<ClCompile Include="src\main.cpp" /> <ClCompile Include="src\main.cpp" />
<ClCompile Include="src\mesh.cpp" /> <ClCompile Include="src\mesh.cpp" />

View File

@@ -60,6 +60,9 @@
<ClInclude Include="src\world.h"> <ClInclude Include="src\world.h">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\engine.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\main.cpp"> <ClCompile Include="src\main.cpp">
@@ -95,6 +98,9 @@
<ClCompile Include="src\world.cpp"> <ClCompile Include="src\world.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\engine.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="data\fragment.glsl"> <None Include="data\fragment.glsl">