feat: engine class
This commit is contained in:
		
							
								
								
									
										197
									
								
								src/engine.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/engine.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										50
									
								
								src/engine.h
									
									
									
									
									
										Normal 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_ | ||||
| @@ -37,7 +37,7 @@ public: | ||||
|  | ||||
| 	void move(const glm::vec3& vec); | ||||
|  | ||||
| 	virtual void update(float delta_time) | ||||
| 	virtual void update(const float delta_time) | ||||
| 	{ | ||||
| 		// ... | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										139
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -2,144 +2,15 @@ | ||||
| #pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") | ||||
| #endif*/ | ||||
|  | ||||
| #include <iostream> | ||||
| #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 | ||||
| #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<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(); | ||||
| 	engine.initialize(); | ||||
| 	engine.run(); | ||||
| 	engine.destroy(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user