Implement ECS in the renderer. Nothing is shown yet though

This commit is contained in:
Sean Ervin 2022-08-30 19:39:24 -04:00
parent 61ff63bef0
commit 371534a01a
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
14 changed files with 367 additions and 136 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Don't track content of these folders # Don't track content of these folders
.vscode/* .vscode/*
.VSCodeCounter
CMakeFiles/* CMakeFiles/*
.vs/* .vs/*
out/* out/*

View File

@ -1,4 +1,6 @@
#include "simpleengine/camera.h" #include "simpleengine/camera.h"
#include "simpleengine/ecs/component/model_componenet.h"
#include "simpleengine/ecs/entity.h"
#include "simpleengine/gfx/light.h" #include "simpleengine/gfx/light.h"
#include "simpleengine/gfx/material.h" #include "simpleengine/gfx/material.h"
#include "simpleengine/gfx/model.h" #include "simpleengine/gfx/model.h"
@ -13,7 +15,7 @@
#include <simpleengine/vertex.h> #include <simpleengine/vertex.h>
#include <simpleengine/gfx/shaders/core_3d_shader.h> #include <simpleengine/gfx/shaders/core_3d_shader.h>
#include <simpleengine/scene.h> //#include <simpleengine/scene.h>
#include <glm/ext/matrix_clip_space.hpp> #include <glm/ext/matrix_clip_space.hpp>
#include <glm/fwd.hpp> #include <glm/fwd.hpp>
@ -141,14 +143,25 @@ int main(int argc, char *argv[]) {
se::gfx::Material material(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f); se::gfx::Material material(white_texture, 1.f, 0.f, 0.f, 0.f, 0.f);
auto cube = std::make_shared<se::gfx::Model>(cube_vertices, cube_indicies, auto entity = std::make_shared<simpleengine::Entity>();
se::gfx::Model model(cube_vertices, cube_indicies, std::optional<se::gfx::Material>(material));
model.calculate_normals();
se::ModelComponent model_component(model);
entity->add_component(model_component);
entity->translate(3.5f, 0.f, 0.f);
/* auto cube = std::make_shared<se::gfx::Model>(cube_vertices, cube_indicies,
std::optional<se::gfx::Material>(material)); std::optional<se::gfx::Material>(material));
cube->calculate_normals(); cube->calculate_normals();
cube->translate(3.5f, 0.f, 0.f); cube->translate(3.5f, 0.f, 0.f); */
//game.add_event(cube); //game.add_event(cube);
/* auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader); auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader);
renderer->add_model(white_texture, cube); renderer->submit_entity(entity);
game.add_event(renderer);
/* renderer->add_model(white_texture, cube);
game.add_event(renderer); */ game.add_event(renderer); */
/* auto r_event = std::make_shared<RendererEvent>(renderer); /* auto r_event = std::make_shared<RendererEvent>(renderer);
@ -157,5 +170,9 @@ int main(int argc, char *argv[]) {
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
game.add_event(camera); game.add_event(camera);
return game.run(); int res = game.run();
renderer->destroy();
return res;
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "gfx/model.h" #include "../../gfx/model.h"
#include "event/event.h" #include "../../event/event.h"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
@ -12,16 +12,20 @@ namespace simpleengine {
* *
*/ */
class Component : public simpleengine::Event { class Component : public simpleengine::Event {
private:
static uint32_t incrementing_handle;
uint32_t handle;
public: public:
Component() = default; Component() {
handle = incrementing_handle++;
}
uint32_t get_handle() {
return handle;
}
virtual void update(const float& delta_time) override { virtual void update(const float& delta_time) override {
std::cout << "Component update" << std::endl; std::cout << "Component update" << std::endl;
} }
virtual std::vector<std::shared_ptr<gfx::Model>> get_renderable_models() {
std::cout << "Got renderables" << std::endl;
return {};
}
}; };
} }

View File

@ -0,0 +1,28 @@
#pragma once
#include "component.h"
#include "../../gfx/model.h"
#include "../../gfx/material.h"
#include <iostream>
#include <vector>
namespace simpleengine {
/**
* @brief A Model is a object that will be shown on the screen by a renderer.
*
*/
class ModelComponent : public simpleengine::Component {
public:
gfx::Model model;
//gfx::Material material;
ModelComponent(gfx::Model model) : model(model) {
}
virtual void update(const float& delta_time) override {
std::cout << "Model Component update" << std::endl;
}
};
}

View File

@ -0,0 +1,103 @@
#pragma once
#include "component/component.h"
#include "../transformable.h"
#include "../util.h"
#include <iterator>
#include <vector>
#include <iostream>
#include <chrono>
#include <random>
#include <bitset>
#include <type_traits>
namespace simpleengine {
/**
* @brief A Model is a object that will be shown on the screen by a renderer.
*
*/
class Entity : public simpleengine::Event, public simpleengine::Transformable {
private:
static uint32_t incrementing_handle;
uint32_t handle;
public:
std::vector<std::shared_ptr<Component>> components;
Entity() : components({}) {
handle = incrementing_handle++;
}
/* Entity() : components({}) {
std::random_device rd; // obtain a random number from hardware
std::mt19937 gen(rd()); // seed the generator
std::uniform_int_distribution<uint16_t> distr(1, std::numeric_limits<std::uint16_t>::max());
uint16_t num = distr(gen);
uint32_t pid = simpleengine::util::get_current_pid();
handle |= num;
handle |= (pid << 16);
std::string binary = std::bitset<16>(num).to_string();
std::cout << "Entity handle: " << binary << std::endl;
} */
Entity(std::vector<std::shared_ptr<Component>> components) : Entity() {
this->components = components;
}
uint32_t get_handle() {
return handle;
}
virtual void update(const float& delta_time) override {
std::cout << "Update entity" << std::endl;
for (auto& component : components) {
component->update(delta_time);
}
}
template<typename T>
bool has_component() const {
for (const auto& comp : components) {
if (std::dynamic_pointer_cast<T>(comp)) {
return true;
}
}
return false;
}
template<typename T>
std::shared_ptr<T> get_component() const {
for (const auto& comp : components) {
if (std::shared_ptr<T> dyn_comp = std::dynamic_pointer_cast<T>(comp); dyn_comp) {
return dyn_comp;
}
}
return nullptr;
}
template<typename T>
void add_component(std::shared_ptr<T> component) {
static_assert(std::is_base_of_v<Component, T>, "Component class must derive from simpleengine::Component");
// Only allow one type of the same component
assert(!has_component<T>()); // TODO: Don't assert, give an error
components.push_back(component);
}
template<typename T>
void add_component(T component) {
static_assert(std::is_base_of_v<Component, T>, "Component class must derive from simpleengine::Component");
// Only allow one type of the same component
assert(!has_component<T>()); // TODO: Don't assert, give an error
components.push_back(std::make_shared<T>(component));
}
};
}

View File

@ -1,46 +0,0 @@
#pragma once
#include "component.h"
#include "transformable.h"
#include <iterator>
#include <vector>
#include <iostream>
namespace simpleengine {
/**
* @brief A Model is a object that will be shown on the screen by a renderer.
*
*/
class Entity : public simpleengine::Event, public simpleengine::Transformable {
public:
std::vector<Component> components;
Entity(std::vector<Component> components = {}) : components(components) {
}
virtual void update(const float& delta_time) override {
std::cout << "Update entity" << std::endl;
for (auto& component : components) {
component.update(delta_time);
}
}
virtual std::vector<std::shared_ptr<gfx::Model>> get_renderable_models() {
std::cout << "Got renderables from entity" << std::endl;
std::vector<std::shared_ptr<gfx::Model>> models;
for (auto& component : components) {
std::vector<std::shared_ptr<gfx::Model>> comp_models = component.get_renderable_models();
// Move comp_models into models
models.insert(models.end(), std::make_move_iterator(comp_models.begin()),
std::make_move_iterator(comp_models.end()));
}
return models;
}
};
}

View File

@ -23,6 +23,7 @@ namespace simpleengine::gfx {
std::vector<LitVertex> vertices; std::vector<LitVertex> vertices;
std::vector<GLuint> indicies; std::vector<GLuint> indicies;
Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material);
Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt); Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(), std::optional<Material> material = std::nullopt);
virtual void update(const float& delta_time) override; virtual void update(const float& delta_time) override;

View File

@ -1,10 +1,13 @@
#pragma once #pragma once
#include "../ecs/entity.h"
#include "material.h"
#include "texture.h" #include "texture.h"
#include "shader.h" #include "shader.h"
//#include "renderable.h" //#include "renderable.h"
#include "model.h" #include "model.h"
#include <unordered_map>
#include <vector> #include <vector>
namespace simpleengine::gfx { namespace simpleengine::gfx {
@ -12,35 +15,58 @@ namespace simpleengine::gfx {
private: private:
GLFWwindow* window; GLFWwindow* window;
public: public:
class RenderingModel { class RenderingBuffers {
public: public:
RenderingModel(std::shared_ptr<simpleengine::gfx::Model> model, simpleengine::gfx::Texture texture, gfx::VBO ebo, gfx::Model& model;
gfx::VBO vbo, gfx::VAO vao) : model(model), texture(texture), ebo(ebo), vbo(vbo), vao(vao) {
}
std::shared_ptr<simpleengine::gfx::Model> model;
simpleengine::gfx::Texture texture;
gfx::VBO ebo; gfx::VBO ebo;
gfx::VBO vbo; gfx::VBO vbo;
gfx::VAO vao; gfx::VAO vao;
RenderingBuffers(gfx::Model& model, gfx::VBO ebo, gfx::VBO vbo, gfx::VAO vao) : model(model), ebo(ebo), vbo(vbo), vao(vao) {
}
/* std::vector<LitVertex>& vertices;
std::vector<GLuint>& indicies; */
/// If these buffers were rendered last update.
//bool rendered;
};
class RenderingModel {
public:
std::shared_ptr<simpleengine::Entity> entity;
std::unordered_map<uint32_t, RenderingBuffers> rendering_buffers;
RenderingModel(std::shared_ptr<simpleengine::Entity> entity) : entity(entity) {
}
/**
* @brief Create and delete buffers for new and old components in entity.
*
*/
void update_buffers();
/**
* @brief Destroy the buffers
*
*/
void destroy_buffers();
}; };
gfx::Shader shader; gfx::Shader shader;
std::vector<RenderingModel> rendering_models; std::unordered_map<uint32_t, RenderingModel> rendering_models;
Renderer(GLFWwindow* window, gfx::Shader shader); Renderer(GLFWwindow* window, gfx::Shader shader);
Renderer(GLFWwindow* window, GLuint shader_program); Renderer(GLFWwindow* window, GLuint shader_program);
virtual void add_model(simpleengine::gfx::Texture texture, std::shared_ptr<simpleengine::gfx::Model> model); virtual void submit_entity(std::shared_ptr<simpleengine::Entity> entity);
virtual void remove_model(std::shared_ptr<simpleengine::gfx::Model> model); virtual bool withdraw_entity(std::shared_ptr<simpleengine::Entity> entity);
virtual void initialize(); virtual void initialize();
virtual void destroy();
virtual void update(const float& delta_time) override { virtual void update(const float& delta_time) override;
}
virtual void render(GLFWwindow* target) override; virtual void render(GLFWwindow* target) override;
}; };

View File

@ -54,7 +54,6 @@ namespace simpleengine::gfx {
GLenum err = glGetError(); GLenum err = glGetError();
if (err != GL_NO_ERROR) { if (err != GL_NO_ERROR) {
fprintf(stderr, "Ran into opengl error: 0x%x\n", err); fprintf(stderr, "Ran into opengl error: 0x%x\n", err);
//std::cerr << "Ran into enum error: "
} }
} }
@ -91,6 +90,12 @@ namespace simpleengine::gfx {
// rarely happens. Modifying other VAOs requires a call to glBindVertexArray anyways so we generally // rarely happens. Modifying other VAOs requires a call to glBindVertexArray anyways so we generally
// don't unbind VAOs (nor VBOs) when it's not directly necessary. // don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0); glBindVertexArray(0);
// TODO: Handle opengl errors EVERYWHERE
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
fprintf(stderr, "Ran into opengl error: 0x%x\n", err);
}
} }
void disable_attrib(const VBO& vbo, GLuint index) const { void disable_attrib(const VBO& vbo, GLuint index) const {

View File

@ -0,0 +1,22 @@
#include <cstdint>
#ifdef _WIN32
#include "windows.h"
#elif __linux__
#include <unistd.h>
#endif
namespace simpleengine {
namespace util {
#ifdef _WIN32
inline uint32_t get_current_pid(LPCTSTR ProcessName) // non-conflicting function name
{
return GetCurrentProcessId();
}
#elif __linux__
inline uint32_t get_current_pid() {
return ::getpid();
}
#endif
}
}

View File

@ -0,0 +1,3 @@
#include "ecs/component/component.h"
uint32_t simpleengine::Component::incrementing_handle = 0;

3
src/ecs/entity.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "ecs/entity.h"
uint32_t simpleengine::Entity::incrementing_handle = 0;

View File

@ -1,6 +1,12 @@
#include "gfx/model.h" #include "gfx/model.h"
#include <optional>
namespace simpleengine::gfx { namespace simpleengine::gfx {
Model::Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, Material material) :
material(std::make_optional(material)), vertices(vertices), indicies(indicies) {
}
Model::Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> material) : Model::Model(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, std::optional<Material> material) :
material(material), vertices(vertices), indicies(indicies) { material(material), vertices(vertices), indicies(indicies) {

View File

@ -1,8 +1,67 @@
#include "gfx/renderer.h" #include "gfx/renderer.h"
#include "ecs/component/component.h"
#include "ecs/entity.h"
#include "gfx/model.h"
#include "renderable.h"
#include "ecs/component/model_componenet.h"
#include <algorithm>
namespace simpleengine::gfx { namespace simpleengine::gfx {
Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) { void Renderer::RenderingModel::update_buffers() {
if (std::shared_ptr<ModelComponent> comp = entity->get_component<simpleengine::ModelComponent>()) {
auto iter = rendering_buffers.find(comp->get_handle());
if (iter == rendering_buffers.end()) {
std::cout << "Creating buffer for ModelComponent (" << comp->get_handle() << ")..." << std::endl;
auto ebo = gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false);
auto vbo = gfx::VBO::init(GL_ARRAY_BUFFER, false);
auto vao = gfx::VAO::init();
auto& model = comp->model;
// Create and setup the EBO, VAO, and VBOs.
vao.bind();
vbo.buffer(model.vertices.data(), 0, sizeof(LitVertex) * model.vertices.size());
if (!model.indicies.empty()) {
ebo.buffer(model.indicies.data(), 0, sizeof(GLuint) * model.indicies.size());
}
// Enable VAO attributes
vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position));
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color));
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal));
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord));
vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id));
RenderingBuffers buffers(comp->model, ebo, vbo, vao);
rendering_buffers.emplace(comp->get_handle(), buffers);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
std::cout << "Finished creating ModelComponent buffers!" << std::endl;
} else {
std::cout << "Already exists" << std::endl;
}
}
}
void Renderer::RenderingModel::destroy_buffers() {
std::cout << "Destroying buffers for entity!" << std::endl;
// Iterate through all buffer lists and destroy each inner buffer.
for (auto& pair : rendering_buffers) {
RenderingBuffers& buffers = pair.second;
buffers.ebo.destroy();
buffers.vao.destroy();
buffers.vbo.destroy();
}
}
Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) {
} }
Renderer::Renderer(GLFWwindow* window, GLuint shader_program): Renderer(window, Renderer::Renderer(GLFWwindow* window, GLuint shader_program): Renderer(window,
@ -10,78 +69,77 @@ namespace simpleengine::gfx {
} }
void Renderer::add_model(simpleengine::gfx::Texture texture, std::shared_ptr<simpleengine::gfx::Model> model) { void Renderer::submit_entity(std::shared_ptr<simpleengine::Entity> entity) {
auto ebo = gfx::VBO::init(GL_ELEMENT_ARRAY_BUFFER, false); std::cout << "Submitting entity (" << entity->get_handle() << ")..." << std::endl;
auto vbo = gfx::VBO::init(GL_ARRAY_BUFFER, false); auto it = rendering_models.emplace(entity->get_handle(), entity);
auto vao = gfx::VAO::init(); it.first->second.update_buffers();
// Create and setup the EBO, VAO, and VBOs.
vao.bind();
vbo.buffer(model->vertices.data(), 0, sizeof(LitVertex) * model->vertices.size());
if (!model->indicies.empty()) {
ebo.buffer(model->indicies.data(), 0, model->indicies.size() * sizeof(GLuint));
}
// Enable VAO attributes
vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position));
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color));
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal));
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord));
vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Create the RenderingModel struct and store it in the vector for later.
RenderingModel rendering_model( model, texture, ebo, vbo, vao);
rendering_models.push_back(rendering_model);
} }
void Renderer::remove_model(std::shared_ptr<simpleengine::gfx::Model> model) { bool Renderer::withdraw_entity(std::shared_ptr<simpleengine::Entity> entity) {
std::cerr << "Removing model is unimplemented!" << std::endl; std::cout << "Withdrawing entity (" << entity->get_handle() << ")...";
auto it = rendering_models.find(entity->get_handle());
if (it != rendering_models.end()) {
it->second.destroy_buffers();
rendering_models.erase(it);
return true;
}
return false;
}
void Renderer::update(const float& delta_time) {
this->render(nullptr);
} }
void Renderer::initialize() { void Renderer::initialize() {
std::cout << "Base Renderer initialized" << std::endl; std::cout << "Base Renderer initialized" << std::endl;
} }
void Renderer::destroy() {
std::cout << "Destroying renderer..." << std::endl;
for (auto& [handle, rendering] : rendering_models) {
rendering.destroy_buffers();
//rendering.entity->destroy();
}
}
void Renderer::render(GLFWwindow* target) { void Renderer::render(GLFWwindow* target) {
shader.use(); shader.use();
for (auto& [handle, rendering] : rendering_models) {
if (rendering.rendering_buffers.size() > 0) {
std::shared_ptr<Entity>& entity = rendering.entity;
for (RenderingModel& rendering : rendering_models) { shader.set_uniform_matrix_4f("transform_matrix", entity->transform_matrix, false);
std::shared_ptr<Model>& model = rendering.model;
for (const auto& pair : rendering.rendering_buffers) {
const RenderingBuffers& buffers = pair.second;
Model& model = buffers.model;
std::optional<Material>& material = model.material;
shader.use(); shader.set_uniform_int("u_textures", 0, false);
shader.set_uniform_matrix_4f("transform_matrix", model->transform_matrix, false);
if (material.has_value()) {
rendering.vao.bind(); //Material& material = material
if (model->indicies.empty()) { shader.set_uniform_float("u_texture_shine", material->shine, false);
glDrawArrays(GL_TRIANGLES, 0, model->vertices.size()); shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false);
} else {
glDrawElements(GL_TRIANGLES, model->indicies.size(), GL_UNSIGNED_INT, 0); glActiveTexture(GL_TEXTURE0);
glBindTextureUnit(0, material->texture.get_texture_id());
material->texture.bind();
}
buffers.vao.bind();
if (model.indicies.empty()) {
glDrawArrays(GL_TRIANGLES, 0, model.vertices.size());
} else {
glDrawElements(GL_TRIANGLES, model.indicies.size(), GL_UNSIGNED_INT, 0);
}
}
} }
/* const Texture& texture = rendering.texture;
shader.set_uniform_matrix_4f("transform_matrix", model->transform_matrix, false);
const int tex_id = 0;
// On a batch renderer, you would set an array.
shader.set_uniform_int("u_textures", tex_id, false);
shader.set_uniform_float("u_texture_shine", 1.f, false);
shader.set_uniform_float("u_texture_reflectivity", 0.f, false);
glActiveTexture(GL_TEXTURE0 + tex_id);
glBindTextureUnit(tex_id, texture.get_texture_id());
texture.bind();
rendering.vao.bind();
if (model->indicies.empty()) {
glDrawArrays(GL_TRIANGLES, 0, model->vertices.size());
} else {
glDrawElements(GL_TRIANGLES, model->indicies.size(), GL_UNSIGNED_INT, 0);
} */
} }
shader.unuse(); shader.unuse();