Merge pull request #1 from SeanOMik/feature/ecs-and-submission-rendering
Feature/ecs and submission rendering
This commit is contained in:
commit
1ea28a8790
|
@ -0,0 +1,10 @@
|
||||||
|
# Get the entt header libraries.
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
entt
|
||||||
|
GIT_REPOSITORY https://github.com/skypjack/entt.git
|
||||||
|
GIT_TAG v3.10.3
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(entt)
|
||||||
|
message("Downloaded entt library to: ${entt_SOURCE_DIR}")
|
||||||
|
set(ENTT_INCLUDE_DIR ${entt_SOURCE_DIR}/src)
|
|
@ -4,6 +4,7 @@ project(SimpleEngine)
|
||||||
|
|
||||||
include(cmrc/CMakeRC.cmake)
|
include(cmrc/CMakeRC.cmake)
|
||||||
include(CMake/GetStbLibraries.cmake)
|
include(CMake/GetStbLibraries.cmake)
|
||||||
|
include(CMake/GetEnTT.cmake)
|
||||||
|
|
||||||
# Add some CMake options:
|
# Add some CMake options:
|
||||||
option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON)
|
option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON)
|
||||||
|
@ -47,11 +48,11 @@ target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
|
||||||
target_link_libraries(simpleengine PUBLIC assimp)
|
target_link_libraries(simpleengine PUBLIC assimp)
|
||||||
target_link_libraries(simpleengine PRIVATE simpleengine_resources)
|
target_link_libraries(simpleengine PRIVATE simpleengine_resources)
|
||||||
|
|
||||||
target_include_directories(simpleengine PUBLIC ${STB_INCLUDE_DIR})
|
|
||||||
|
|
||||||
# Include some dependencies' include directories
|
# Include some dependencies' include directories
|
||||||
target_include_directories(simpleengine PUBLIC ${OPENGL_INCLUDE_DIR})
|
target_include_directories(simpleengine PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||||
target_include_directories(simpleengine PUBLIC ${GLM_INCLUDE_DIRS})
|
target_include_directories(simpleengine PUBLIC ${GLM_INCLUDE_DIRS})
|
||||||
|
target_include_directories(simpleengine PUBLIC ${STB_INCLUDE_DIR})
|
||||||
|
target_include_directories(simpleengine PUBLIC ${ENTT_INCLUDE_DIR})
|
||||||
|
|
||||||
# Add examples as a target if the user has them enabled
|
# Add examples as a target if the user has them enabled
|
||||||
if (SIMPLE_ENGINE_BUILD_EXAMPLES)
|
if (SIMPLE_ENGINE_BUILD_EXAMPLES)
|
||||||
|
|
|
@ -1,5 +1,2 @@
|
||||||
*.blend
|
*
|
||||||
*.obj
|
!shaders
|
||||||
*.png
|
|
||||||
*.bin
|
|
||||||
*.gltf
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "simpleengine/camera.h"
|
#include "simpleengine/camera.h"
|
||||||
#include "simpleengine/ecs/component/mesh_component.h"
|
#include "simpleengine/ecs/component/mesh_component.h"
|
||||||
#include <simpleengine/ecs/component/model_component.h>
|
#include <simpleengine/ecs/component/model_component.h>
|
||||||
|
#include "simpleengine/ecs/component/transform_component.h"
|
||||||
|
#include <simpleengine/ecs/component/rotating_component.h>
|
||||||
#include "simpleengine/ecs/entity.h"
|
#include "simpleengine/ecs/entity.h"
|
||||||
#include "simpleengine/entity_manager.h"
|
|
||||||
#include "simpleengine/gfx/light.h"
|
#include "simpleengine/gfx/light.h"
|
||||||
#include "simpleengine/gfx/material.h"
|
#include "simpleengine/gfx/material.h"
|
||||||
#include "simpleengine/gfx/mesh.h"
|
#include "simpleengine/gfx/mesh.h"
|
||||||
|
@ -10,7 +11,6 @@
|
||||||
#include "simpleengine/gfx/renderer.h"
|
#include "simpleengine/gfx/renderer.h"
|
||||||
#include "simpleengine/gfx/texture.h"
|
#include "simpleengine/gfx/texture.h"
|
||||||
#include "simpleengine/vector.h"
|
#include "simpleengine/vector.h"
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <simpleengine/gfx/shader.h>
|
#include <simpleengine/gfx/shader.h>
|
||||||
#include <simpleengine/renderable.h>
|
#include <simpleengine/renderable.h>
|
||||||
#include <simpleengine/event/event.h>
|
#include <simpleengine/event/event.h>
|
||||||
|
@ -19,8 +19,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/gfx/model.h>
|
#include <simpleengine/gfx/model.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>
|
||||||
|
@ -166,29 +165,45 @@ int main(int argc, char *argv[]) {
|
||||||
5, 6, 12, 12, 6, 13
|
5, 6, 12, 12, 6, 13
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<aiTextureType, std::vector<se::gfx::Texture>> textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<se::gfx::Texture>>> textures;
|
||||||
textures.emplace(white_texture.type, std::vector<se::gfx::Texture>{ white_texture });
|
textures.emplace(white_texture.type, std::vector<std::shared_ptr<se::gfx::Texture>>{ std::make_shared<se::gfx::Texture>(white_texture) });
|
||||||
se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
// Create a renderer
|
||||||
|
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader);
|
||||||
|
game.add_renderable(renderer);
|
||||||
|
|
||||||
|
// Create a Scene and give it the renderer
|
||||||
|
auto scene = std::make_shared<se::Scene>(renderer);
|
||||||
|
game.add_event(scene);
|
||||||
|
|
||||||
|
// Create an Entity in the Scene and add components to it.
|
||||||
|
se::ecs::Entity entity = scene->create_entity();
|
||||||
|
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
||||||
|
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/stall.obj");
|
||||||
|
|
||||||
|
// Backpack model required vertically flipped texture coords.
|
||||||
|
auto& model_comp = entity.add_component<se::ModelComponent>("examples/dev_testing/resources/backpack/backpack.obj");
|
||||||
|
model_comp.model.vertically_flip_tex_coords();
|
||||||
|
|
||||||
|
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/scientist/scientist.fbx");
|
||||||
|
//entity.add_component<se::ModelComponent>("examples/dev_testing/resources/paradigm/paradigm.fbx");
|
||||||
|
//entity.add_component<se::RotatingComponent>();
|
||||||
|
auto& transform_comp = entity.add_component<se::TransformComponent>();
|
||||||
|
transform_comp.translate(15.f, -8.f, 0.f);
|
||||||
|
/* transform_comp.scale(0.1f);
|
||||||
|
transform_comp.rotate_z(-90.f);*/
|
||||||
|
transform_comp.rotate_x(-90.f);
|
||||||
|
|
||||||
|
|
||||||
// Create the entity and add the model component to it.
|
// Create the entity and add the model component to it.
|
||||||
/* auto entity = std::make_shared<simpleengine::Entity>();
|
/* auto entity = std::make_shared<simpleengine::Entity>();
|
||||||
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, white_material, true);
|
entity->add_component<se::MeshComponent>(cube_vertices, cube_indicies, white_material, true);
|
||||||
entity->translate(3.5f, 0.f, 0.f); */
|
entity->translate(3.5f, 0.f, 0.f); */
|
||||||
|
|
||||||
auto entity = std::make_shared<simpleengine::Entity>();
|
/* auto entity = std::make_shared<simpleengine::Entity>();
|
||||||
entity->add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
entity->add_component<se::ModelComponent>("examples/dev_testing/resources/dragon.obj");
|
||||||
entity->translate(12.f, -4.f, 0.f);
|
entity->translate(12.f, -4.f, 0.f); */
|
||||||
|
|
||||||
// Create a renderer and submit the entity into it.
|
|
||||||
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader);
|
|
||||||
renderer->enable_debug();
|
|
||||||
renderer->submit_entity(entity);
|
|
||||||
game.add_renderable(renderer);
|
|
||||||
|
|
||||||
// Create an EntityManager, and submit the entity into it.
|
|
||||||
auto ecs_manager = std::make_shared<se::EntityManager>();
|
|
||||||
ecs_manager->submit_entity(entity);
|
|
||||||
game.add_event(ecs_manager);
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../../gfx/mesh.h"
|
|
||||||
#include "../../event/event.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace simpleengine {
|
|
||||||
/**
|
|
||||||
* @brief A Model is a object that will be shown on the screen by a renderer.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Component : public simpleengine::Event {
|
|
||||||
private:
|
|
||||||
static uint32_t incrementing_handle;
|
|
||||||
uint32_t handle;
|
|
||||||
public:
|
|
||||||
Component() {
|
|
||||||
handle = incrementing_handle++;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_handle() {
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
|
||||||
std::cout << "Component update" << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "component.h"
|
|
||||||
#include "../../gfx/mesh.h"
|
#include "../../gfx/mesh.h"
|
||||||
#include "../../gfx/material.h"
|
#include "../../gfx/material.h"
|
||||||
|
|
||||||
|
@ -9,37 +8,32 @@
|
||||||
|
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
/**
|
/**
|
||||||
* @brief A Model is a object that will be shown on the screen by a renderer.
|
* @brief A component that contains a Mesh that will be rendered.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class MeshComponent : public simpleengine::Component {
|
class MeshComponent {
|
||||||
public:
|
public:
|
||||||
gfx::Mesh model;
|
gfx::Mesh mesh;
|
||||||
//gfx::Material material;
|
|
||||||
|
|
||||||
MeshComponent(gfx::Mesh model) : model(model) {
|
MeshComponent(gfx::Mesh mesh) : mesh(mesh) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, gfx::Material material,
|
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies, gfx::Material material,
|
||||||
bool calculate_normals = false): model(vertices, indicies, material) {
|
bool calculate_normals = false): mesh(vertices, indicies, material) {
|
||||||
|
|
||||||
if (calculate_normals) {
|
if (calculate_normals) {
|
||||||
model.calculate_normals();
|
mesh.calculate_normals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(),
|
MeshComponent(std::vector<LitVertex> vertices, std::vector<GLuint> indicies = std::vector<GLuint>(),
|
||||||
std::optional<gfx::Material> material = std::nullopt, bool calculate_normals = false) :
|
std::optional<gfx::Material> material = std::nullopt, bool calculate_normals = false) :
|
||||||
model(vertices, indicies, material) {
|
mesh(vertices, indicies, material) {
|
||||||
|
|
||||||
if (calculate_normals) {
|
if (calculate_normals) {
|
||||||
model.calculate_normals();
|
mesh.calculate_normals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "component.h"
|
|
||||||
#include "../../gfx/model.h"
|
#include "../../gfx/model.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -8,10 +7,10 @@
|
||||||
|
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
/**
|
/**
|
||||||
* @brief A Model is a object that will be shown on the screen by a renderer.
|
* @brief A component that contains a Model that will be rendered.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ModelComponent : public simpleengine::Component {
|
class ModelComponent {
|
||||||
public:
|
public:
|
||||||
gfx::Model model;
|
gfx::Model model;
|
||||||
|
|
||||||
|
@ -19,12 +18,9 @@ namespace simpleengine {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelComponent(std::string model_file_path) : model(model_file_path) {
|
ModelComponent(std::string model_file_path, int model_processing_flags = gfx::ModelProcessingFlags::MdlProcFlag_NONE,
|
||||||
|
int assimp_flags = 0) : model(model_file_path, model_processing_flags, assimp_flags) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
/**
|
||||||
|
* @brief A component that will rotate the transform every frame.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class RotatingComponent {
|
||||||
|
public:
|
||||||
|
float rate;
|
||||||
|
glm::vec3 rotation_axis;
|
||||||
|
|
||||||
|
RotatingComponent() : rate(10.f), rotation_axis(glm::vec3(0, 1, 0)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RotatingComponent(float rate) : rate(rate), rotation_axis(glm::vec3(0, 1, 0)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RotatingComponent(glm::vec3 rotation_axis) : rotation_axis(rotation_axis) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RotatingComponent(float rate, glm::vec3 rotation_axis) : rate(rate), rotation_axis(rotation_axis) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
/**
|
||||||
|
* @brief A component that contains a Mesh that will be rendered.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class TransformComponent {
|
||||||
|
public:
|
||||||
|
glm::mat4 transform_matrix;
|
||||||
|
|
||||||
|
TransformComponent() : transform_matrix(glm::mat4(1.f)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
friend TransformComponent operator+(TransformComponent lhs, const TransformComponent& rhs) {
|
||||||
|
lhs.transform_matrix += rhs.transform_matrix;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend TransformComponent operator-(TransformComponent lhs, const TransformComponent& rhs) {
|
||||||
|
lhs.transform_matrix -= rhs.transform_matrix;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend TransformComponent operator*(TransformComponent lhs, const TransformComponent& rhs) {
|
||||||
|
lhs.transform_matrix *= rhs.transform_matrix;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend TransformComponent operator/(TransformComponent lhs, const TransformComponent& rhs) {
|
||||||
|
lhs.transform_matrix /= rhs.transform_matrix;
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void combine_transform(const glm::mat4& transform_matrix) {
|
||||||
|
this->transform_matrix *= transform_matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void combine_transform(const TransformComponent& transformable) {
|
||||||
|
transform_matrix = transformable.transform_matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void translate(float x, float y, float z) {
|
||||||
|
transform_matrix = glm::translate(transform_matrix, glm::vec3(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual void translate(const glm::vec3& vec) {
|
||||||
|
transform_matrix = glm::translate(transform_matrix, vec);
|
||||||
|
} */
|
||||||
|
|
||||||
|
virtual glm::mat4 rotation_matrix(float degrees, glm::vec3 rotation_axis) const {
|
||||||
|
return glm::rotate(transform_matrix, glm::radians(degrees), rotation_axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual glm::mat4 rotation_x_matrix(float degrees) const {
|
||||||
|
return rotation_matrix(degrees, glm::vec3(1, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual glm::mat4 rotation_y_matrix(float degrees) const {
|
||||||
|
return rotation_matrix(degrees, glm::vec3(0, 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual glm::mat4 rotation_z_matrix(float degrees) const {
|
||||||
|
return rotation_matrix(degrees, glm::vec3(0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void rotate(float degrees, glm::vec3 rotation_axis) {
|
||||||
|
transform_matrix = rotation_matrix(degrees, rotation_axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void rotate_x(float degrees) {
|
||||||
|
transform_matrix = rotation_x_matrix(degrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void rotate_y(float degrees) {
|
||||||
|
transform_matrix = rotation_y_matrix(degrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void rotate_z(float degrees) {
|
||||||
|
transform_matrix = rotation_z_matrix(degrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void scale(glm::vec3 scalar_vec) {
|
||||||
|
transform_matrix = glm::scale(transform_matrix, scalar_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void scale(float scalar) {
|
||||||
|
transform_matrix = glm::scale(transform_matrix, glm::vec3(scalar, scalar, scalar));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,116 +1,266 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "component/component.h"
|
#include "entt/entity/fwd.hpp"
|
||||||
#include "../transformable.h"
|
#include <cstddef>
|
||||||
#include "../util.h"
|
#include <entt/entt.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <iterator>
|
namespace simpleengine::ecs {
|
||||||
#include <vector>
|
class Entity {
|
||||||
#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 {
|
|
||||||
// TODO: Don't extend from Event, create own destroy function
|
|
||||||
private:
|
private:
|
||||||
static uint32_t incrementing_handle;
|
entt::registry& registry;
|
||||||
uint32_t handle;
|
entt::entity inner;
|
||||||
public:
|
public:
|
||||||
std::vector<std::shared_ptr<Component>> components;
|
/* Entity(entt::entity entity) : inner(entity) {
|
||||||
|
|
||||||
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() {
|
Entity(entt::registry& registry, entt::entity entity) : registry(registry), inner(entity) {
|
||||||
this->components = components;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_handle() {
|
/**
|
||||||
return handle;
|
* @brief Checks if an identifier refers to a valid entity.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a1795b1221d728f806319a685930f520d
|
||||||
|
*
|
||||||
|
* @return true if the identifier is valid
|
||||||
|
* @return false otherwise
|
||||||
|
*/
|
||||||
|
bool is_valid() const {
|
||||||
|
return registry.valid(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
/**
|
||||||
for (auto& component : components) {
|
* @brief Returns the actual version for an identifier.
|
||||||
component->update(delta_time);
|
*
|
||||||
}
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a199babc787d6baa6f7ccce761228a5f6
|
||||||
|
*
|
||||||
rotate_y(delta_time * 10); // TODO: Remove
|
* @return entt::registry::version_type The version for the given identifier if valid, the tombstone version otherwise.
|
||||||
|
*/
|
||||||
|
entt::registry::version_type current_version() const {
|
||||||
|
return registry.current(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
/**
|
||||||
bool has_component() const {
|
* @brief Releases an identifier.
|
||||||
for (const auto& comp : components) {
|
*
|
||||||
if (std::dynamic_pointer_cast<T>(comp)) {
|
* The version is updated and the identifier can be recycled at any time.
|
||||||
return true;
|
*
|
||||||
}
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a3d9cb2368384b0952cb54848e777359e
|
||||||
}
|
*
|
||||||
|
* @return entt::registry::version_type The version of the recycled entity.
|
||||||
return false;
|
*/
|
||||||
|
entt::registry::version_type release() {
|
||||||
|
return registry.release(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
/**
|
||||||
std::shared_ptr<T> get_component() const {
|
* @brief Releases an identifier.
|
||||||
for (const auto& comp : components) {
|
*
|
||||||
if (std::shared_ptr<T> dyn_comp = std::dynamic_pointer_cast<T>(comp); dyn_comp) {
|
* The suggested version or the valid version closest to the suggested one is used instead of the implicitly generated version.
|
||||||
return dyn_comp;
|
*
|
||||||
}
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#af9c919867fc93a7e1a2d0762ac3a9877
|
||||||
}
|
*
|
||||||
|
* @param version A desired version upon destruction.
|
||||||
return nullptr;
|
* @return entt::registry::version_type The version actually assigned to the entity.
|
||||||
|
*/
|
||||||
|
entt::registry::version_type release(entt::registry::version_type version) {
|
||||||
|
return registry.release(inner, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
/**
|
||||||
void add_component(std::shared_ptr<T> component) {
|
* @brief Destroys an entity and releases its identifier.
|
||||||
static_assert(std::is_base_of_v<Component, T>, "Component class must derive from simpleengine::Component");
|
*
|
||||||
|
* @warning Adding or removing components to an entity that is being destroyed can result in undefined behavior. Attempting to use an invalid entity results in undefined behavior.
|
||||||
// Only allow one type of the same component
|
*
|
||||||
assert(!has_component<T>()); // TODO: Don't assert, give an error
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a7b2c0368d508a6af2d094a9fc592a4a0
|
||||||
components.push_back(component);
|
*
|
||||||
|
* @return entt::registry::version_type The version of the recycled entity.
|
||||||
|
*/
|
||||||
|
entt::registry::version_type destroy() {
|
||||||
|
return registry.destroy(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
/**
|
||||||
void add_component(T component) {
|
* @brief Destroys an entity and releases its identifier.
|
||||||
static_assert(std::is_base_of_v<Component, T>, "Component class must derive from simpleengine::Component");
|
*
|
||||||
|
* The suggested version or the valid version closest to the suggested one is used instead of the implicitly generated version.
|
||||||
// Only allow one type of the same component
|
*
|
||||||
assert(!has_component<T>()); // TODO: Don't assert, give an error
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#adc175a0d3bcf83a133c63890c674ceb3
|
||||||
components.push_back(std::make_shared<T>(component));
|
*
|
||||||
|
* @param version A desired version upon destruction.
|
||||||
|
* @return entt::registry::version_type The version actually assigned to the entity.
|
||||||
|
*/
|
||||||
|
entt::registry::version_type destroy(entt::registry::version_type version) {
|
||||||
|
return registry.destroy(inner, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ...Args>
|
/**
|
||||||
std::shared_ptr<T> add_component(Args&&... args) {
|
* @brief Assigns the given component to an entity.
|
||||||
static_assert(std::is_base_of_v<Component, T>, "Component class must derive from simpleengine::Component");
|
*
|
||||||
|
* The component must have a proper constructor or be of aggregate type.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity or to assign a component to an entity that already owns it results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a4c9c0532972adc7a930a50888a97efdf
|
||||||
|
*
|
||||||
|
* @tparam Component Type of component to create.
|
||||||
|
* @tparam Args Types of arguments to use to construct the component.
|
||||||
|
*
|
||||||
|
* @param args Parameters to use to initialize the component.
|
||||||
|
*
|
||||||
|
* @return decltype(auto) A reference to the newly created component.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Args>
|
||||||
|
decltype(auto) add_component(Args&&... args) {
|
||||||
|
return registry.emplace<Component>(inner, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
// Only allow one type of the same component
|
/**
|
||||||
assert(!has_component<T>()); // TODO: Don't assert, give an error
|
* @brief Assigns or replaces the given component for an entity.
|
||||||
auto comp = std::make_shared<T>(std::forward<Args>(args)...);
|
*
|
||||||
components.push_back(comp);
|
* The component must have a proper constructor or be of aggregate type.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity or to assign a component to an entity that already owns it results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a3bbaebbb9365eef262453e42a8f7dc4b
|
||||||
|
*
|
||||||
|
* @tparam Component Type of component to assign or replace.
|
||||||
|
* @tparam Args Types of arguments to use to construct the component.
|
||||||
|
*
|
||||||
|
* @param args Parameters to use to initialize the component.
|
||||||
|
*
|
||||||
|
* @return decltype(auto) A reference to the newly created component.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Args>
|
||||||
|
decltype(auto) add_or_replace_component(Args&&... args) {
|
||||||
|
return registry.emplace_or_replace<Component>(inner, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
return comp;
|
/**
|
||||||
|
* @brief Replaces the given component for an entity.
|
||||||
|
*
|
||||||
|
* The component must have a proper constructor or be of aggregate type.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity or to replace a component of an entity that doesn't own it results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a0501ff5a96a3421f3eec427bf5d62380
|
||||||
|
*
|
||||||
|
* @tparam Component Type of component to replace.
|
||||||
|
* @tparam Args Types of arguments to use to construct the component.
|
||||||
|
*
|
||||||
|
* @param args Parameters to use to initialize the component.
|
||||||
|
*
|
||||||
|
* @return decltype(auto) A reference to the component being replaced.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Args>
|
||||||
|
decltype(auto) replace_component(Args&&... args) {
|
||||||
|
return registry.replace<Component>(inner, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Patches the given component for an entity.
|
||||||
|
*
|
||||||
|
* The signature of the function should be equivalent to the following:
|
||||||
|
* \code{.cpp}
|
||||||
|
* void(Component &);
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* @note Empty types aren't explicitly instantiated and therefore they are never returned. However, this function can be used to trigger an update signal for them.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity or to patch a component of an entity that doesn't own it results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a22454253689ff77e41326f849bfea976
|
||||||
|
*
|
||||||
|
* @tparam Component Type of component to patch.
|
||||||
|
* @tparam Func Types of the function objects to invoke.
|
||||||
|
*
|
||||||
|
* @param func Valid function objects.
|
||||||
|
*
|
||||||
|
* @return decltype(auto) A reference to the patched component.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Func>
|
||||||
|
decltype(auto) patch(Func&&... func) {
|
||||||
|
return registry.patch<Component>(inner, std::forward<Func>(func)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes the given components from an entity.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#aa66ca71c5eb6c2e1b3bde6ff86a268c7
|
||||||
|
*
|
||||||
|
* @tparam Component Type of component to remove.
|
||||||
|
* @tparam Other Other types of components to remove.
|
||||||
|
*
|
||||||
|
* @return size_t The number of components actually removed.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Other>
|
||||||
|
size_t remove_components() {
|
||||||
|
return registry.remove<Component, Other...>(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erases the given components from an entity.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity or to erase a component from an entity that doesn't own it results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#ad7a51ade7ff181d7aa0b35915d0a4f2b
|
||||||
|
*
|
||||||
|
* @tparam Component Types of components to erase.
|
||||||
|
* @tparam Other Other types of components to erase.
|
||||||
|
*/
|
||||||
|
template<typename Component, typename... Other>
|
||||||
|
void erase() {
|
||||||
|
return registry.remove<Component, Other...>(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if an entity has all the given components.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a40072eca607846f43f47d0e3f11dd196
|
||||||
|
*
|
||||||
|
* @tparam Component Components for which to perform the check.
|
||||||
|
*
|
||||||
|
* @return true if the entity has all the components
|
||||||
|
* @return false otherwise
|
||||||
|
*/
|
||||||
|
template<typename... Component>
|
||||||
|
bool has_all_of() const {
|
||||||
|
return registry.all_of<Component...>(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if an entity has at least one of the given components.
|
||||||
|
*
|
||||||
|
* @warning Attempting to use an invalid entity results in undefined behavior.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a08f819276fd2d8b2b2b6d01357f61a42
|
||||||
|
*
|
||||||
|
* @tparam Component Components for which to perform the check.
|
||||||
|
*
|
||||||
|
* @return true if the entity has at least one of the given components
|
||||||
|
* @return false otherwise
|
||||||
|
*/
|
||||||
|
template<typename... Component>
|
||||||
|
bool has_any_of() const {
|
||||||
|
return registry.any_of<Component...>(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if an entity has components assigned.
|
||||||
|
*
|
||||||
|
* @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a10f5e61d4cabab9e9c1e87edc30de551
|
||||||
|
*
|
||||||
|
* @return true if the entity has no components assigned
|
||||||
|
* @return false otherwise
|
||||||
|
*/
|
||||||
|
bool has_any_components() const {
|
||||||
|
return registry.orphan(inner);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ecs/entity.h"
|
|
||||||
#include "event/event.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace simpleengine {
|
|
||||||
class EntityManager : public simpleengine::Event {
|
|
||||||
public:
|
|
||||||
std::unordered_map<uint32_t, std::shared_ptr<simpleengine::Entity>> entities;
|
|
||||||
|
|
||||||
EntityManager();
|
|
||||||
|
|
||||||
virtual void submit_entity(std::shared_ptr<simpleengine::Entity> entity);
|
|
||||||
virtual bool withdraw_entity(std::shared_ptr<simpleengine::Entity> entity);
|
|
||||||
|
|
||||||
virtual void initialize();
|
|
||||||
virtual void destroy() override;
|
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -3,12 +3,14 @@
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
class Material {
|
class Material {
|
||||||
public:
|
public:
|
||||||
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
||||||
|
|
||||||
float ambient_scalar;
|
float ambient_scalar;
|
||||||
float diffuse_scalar;
|
float diffuse_scalar;
|
||||||
|
@ -16,7 +18,7 @@ namespace simpleengine::gfx {
|
||||||
float shine;
|
float shine;
|
||||||
float reflectivity;
|
float reflectivity;
|
||||||
|
|
||||||
Material(std::unordered_map<aiTextureType, std::vector<Texture>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
|
Material(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures, float shine = 1.f, float reflectivity = 0.f, float specular_scalar = 0.f, float ambient_scalar = 0.f, float diffuse_scalar = 0.f) :
|
||||||
textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
|
textures(textures), ambient_scalar(ambient_scalar), diffuse_scalar(diffuse_scalar), specular_scalar(specular_scalar),
|
||||||
shine(shine), reflectivity(reflectivity) {
|
shine(shine), reflectivity(reflectivity) {
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace simpleengine::gfx {
|
||||||
std::vector<LitVertex> vertices;
|
std::vector<LitVertex> vertices;
|
||||||
std::vector<GLuint> indicies;
|
std::vector<GLuint> indicies;
|
||||||
|
|
||||||
|
bool are_buffers_created = false;
|
||||||
gfx::VBO ebo;
|
gfx::VBO ebo;
|
||||||
gfx::VBO vbo;
|
gfx::VBO vbo;
|
||||||
gfx::VAO vao;
|
gfx::VAO vao;
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
//#include <assimp/mesh.h>
|
//#include <assimp/mesh.h>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
|
enum ModelProcessingFlags : uint8_t {
|
||||||
|
MdlProcFlag_NONE = 0b00000000,
|
||||||
|
MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY = 0b00000001,
|
||||||
|
MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY = 0b00000010,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A Model is a group of Meshes read from the 3D model file.
|
* @brief A Model is a group of Meshes read from the 3D model file.
|
||||||
*
|
*
|
||||||
|
@ -20,14 +26,25 @@ namespace simpleengine::gfx {
|
||||||
class Model : public simpleengine::Transformable {
|
class Model : public simpleengine::Transformable {
|
||||||
protected:
|
protected:
|
||||||
std::string model_directory; // May be needed
|
std::string model_directory; // May be needed
|
||||||
|
int additional_assimp_flags;
|
||||||
|
int model_processing_flags;
|
||||||
public:
|
public:
|
||||||
std::vector<gfx::Mesh> meshes;
|
std::vector<gfx::Mesh> meshes;
|
||||||
|
|
||||||
Model(std::string file_path);
|
Model(std::string file_path, int model_processing_flags = ModelProcessingFlags::MdlProcFlag_NONE, int assimp_flags = 0);
|
||||||
|
|
||||||
void load_model(std::string path);
|
void load_model(std::string path);
|
||||||
void process_node(aiNode* node, const aiScene* scene);
|
void process_node(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiNode* node, const aiScene* scene);
|
||||||
gfx::Mesh process_mesh(aiMesh* mesh, const aiScene* scene);
|
gfx::Mesh process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene);
|
||||||
std::vector<Texture> load_material_textures(aiMaterial* material, aiTextureType type);
|
|
||||||
|
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material);
|
||||||
|
std::vector<std::shared_ptr<Texture>> load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void post_process();
|
||||||
|
public:
|
||||||
|
|
||||||
|
void vertically_flip_tex_coords();
|
||||||
|
void horizontally_flip_tex_coords();
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -1,45 +1,29 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../ecs/entity.h"
|
|
||||||
#include "material.h"
|
|
||||||
#include "texture.h"
|
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
//#include "renderable.h"
|
#include "simpleengine/gfx/mesh.h"
|
||||||
#include "mesh.h"
|
|
||||||
#include "model.h"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
|
class RenderingJob {
|
||||||
|
public:
|
||||||
|
gfx::Mesh& rendering_mesh;
|
||||||
|
glm::mat4 transform_mat;
|
||||||
|
|
||||||
|
RenderingJob(gfx::Mesh& mesh, glm::mat4 position) : rendering_mesh(mesh), transform_mat(position) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Renderer : public simpleengine::Renderable {
|
class Renderer : public simpleengine::Renderable {
|
||||||
private:
|
private:
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class RenderingModel {
|
std::queue<RenderingJob> rendering_queue;
|
||||||
public:
|
|
||||||
std::shared_ptr<simpleengine::Entity> entity;
|
|
||||||
std::unordered_map<uint32_t, gfx::Mesh&> component_models;
|
|
||||||
|
|
||||||
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();
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unordered_map<uint32_t, RenderingModel> rendering_models;
|
|
||||||
gfx::Shader shader;
|
gfx::Shader shader;
|
||||||
|
|
||||||
Renderer(GLFWwindow* window, gfx::Shader shader);
|
Renderer(GLFWwindow* window, gfx::Shader shader);
|
||||||
|
@ -47,8 +31,8 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
void enable_debug();
|
void enable_debug();
|
||||||
|
|
||||||
virtual void submit_entity(std::shared_ptr<simpleengine::Entity> entity);
|
virtual void queue_job(RenderingJob job);
|
||||||
virtual bool withdraw_entity(std::shared_ptr<simpleengine::Entity> entity);
|
virtual void create_job_buffers(RenderingJob& job);
|
||||||
|
|
||||||
virtual void initialize();
|
virtual void initialize();
|
||||||
virtual void destroy() override;
|
virtual void destroy() override;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
@ -17,6 +18,13 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
|
enum TextureFlags : uint8_t {
|
||||||
|
TexFlags_IMG_2D = 0b00000001,
|
||||||
|
TexFlags_FLIP_VERTICALLY = 0b00000010,
|
||||||
|
TexFlags_FLIP_HORIZONTALLY = 0b00000100,
|
||||||
|
TexFlags_MIPMAP = 0b00001000,
|
||||||
|
};
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
private:
|
private:
|
||||||
unsigned char* img_data; // TODO Free this if its not used anymore
|
unsigned char* img_data; // TODO Free this if its not used anymore
|
||||||
|
@ -30,6 +38,7 @@ namespace simpleengine::gfx {
|
||||||
int width;
|
int width;
|
||||||
int channels;
|
int channels;
|
||||||
aiTextureType type;
|
aiTextureType type;
|
||||||
|
std::string path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Texture object from a path.
|
* @brief Construct a new Texture object from a path.
|
||||||
|
@ -38,7 +47,8 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
Texture(const char* path, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
||||||
|
TextureFlags::TexFlags_MIPMAP);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Texture object from the loaded file buffer.
|
* @brief Construct a new Texture object from the loaded file buffer.
|
||||||
|
@ -48,7 +58,8 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
||||||
|
TextureFlags::TexFlags_MIPMAP);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new Texture object from the loaded file buffer.
|
* @brief Construct a new Texture object from the loaded file buffer.
|
||||||
|
@ -57,7 +68,8 @@ namespace simpleengine::gfx {
|
||||||
* @param img_2d Whether or not the texture is 2D.
|
* @param img_2d Whether or not the texture is 2D.
|
||||||
* @param mipmap Whether or not to generate mipmaps for this texture.
|
* @param mipmap Whether or not to generate mipmaps for this texture.
|
||||||
*/
|
*/
|
||||||
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, bool img_2d = true, bool mipmap = true);
|
Texture(std::vector<unsigned char> buffer, aiTextureType type = aiTextureType::aiTextureType_DIFFUSE, int flags = TextureFlags::TexFlags_IMG_2D |
|
||||||
|
TextureFlags::TexFlags_MIPMAP);
|
||||||
|
|
||||||
static Texture white_texture();
|
static Texture white_texture();
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,32 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "entt/entity/fwd.hpp"
|
||||||
#include "gfx/mesh.h"
|
#include "gfx/mesh.h"
|
||||||
#include "entity.h"
|
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
#include "renderable.h"
|
#include "renderable.h"
|
||||||
|
#include "simpleengine/gfx/renderer.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
|
||||||
namespace simpleengine {
|
namespace simpleengine {
|
||||||
|
namespace ecs {
|
||||||
|
class Entity;
|
||||||
|
}
|
||||||
|
|
||||||
class Scene : public simpleengine::Event {
|
class Scene : public simpleengine::Event {
|
||||||
|
protected:
|
||||||
|
entt::registry registry;
|
||||||
|
std::shared_ptr<gfx::Renderer> renderer;
|
||||||
public:
|
public:
|
||||||
/**
|
Scene(std::shared_ptr<gfx::Renderer> renderer);
|
||||||
* @brief A list of entities in this scene.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
std::vector<std::shared_ptr<Entity>> entities;
|
|
||||||
|
|
||||||
/**
|
ecs::Entity create_entity();
|
||||||
* @brief Models that don't belong to an entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
std::vector<std::shared_ptr<gfx::Model>> stray_models;
|
|
||||||
|
|
||||||
Scene() = default;
|
virtual void update(const float& delta_time) override;
|
||||||
|
|
||||||
void add_entity(std::shared_ptr<Entity> entity) {
|
|
||||||
entities.push_back(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_stray_model(std::shared_ptr<gfx::Model> stray) {
|
|
||||||
stray_models.push_back(stray);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update(const float& delta_time) override {
|
|
||||||
for (auto& entity : entities) {
|
|
||||||
entity->update(delta_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -12,6 +12,5 @@ pkgs.mkShell {
|
||||||
glfw
|
glfw
|
||||||
glm
|
glm
|
||||||
assimp
|
assimp
|
||||||
(callPackage ./soil2.nix { })
|
|
||||||
];
|
];
|
||||||
}
|
}
|
37
soil2.nix
37
soil2.nix
|
@ -1,37 +0,0 @@
|
||||||
{ lib
|
|
||||||
, stdenv
|
|
||||||
, fetchFromGitHub
|
|
||||||
, cmake
|
|
||||||
, libGL
|
|
||||||
, libX11
|
|
||||||
}:
|
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
version = "39028e64921c03cabbc53b937da4a85aba264e00";
|
|
||||||
pname = "soil2";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "SpartanJ";
|
|
||||||
repo = pname;
|
|
||||||
rev = version;
|
|
||||||
sha256 = "sha256-zQQ8lwOkMCxdlf6zfnIOYVUTGVqnJuHL/LL8fbzxwHY=";
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake libGL libX11 ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
cmake --build . --target install --config Release
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "SOIL2 is a tiny C library used primarily for uploading textures into OpenGL.";
|
|
||||||
homepage = "https://github.com/SpartanJ/SOIL2";
|
|
||||||
license = licenses.mit0;
|
|
||||||
platforms = platforms.unix;
|
|
||||||
maintainers = with maintainers; [ seanomik ];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -63,19 +63,19 @@ namespace simpleengine {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
|
||||||
rotation.z += camera_speed;
|
rotation.z += camera_speed * .3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
|
||||||
rotation.z -= camera_speed;
|
rotation.z -= camera_speed * .3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
|
||||||
rotation.y -= camera_speed;
|
rotation.y -= camera_speed * .3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
|
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
|
||||||
rotation.y += camera_speed;
|
rotation.y += camera_speed * .3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the pitch of the camera.
|
// Limit the pitch of the camera.
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#include "ecs/component/component.h"
|
|
||||||
|
|
||||||
uint32_t simpleengine::Component::incrementing_handle = 0;
|
|
|
@ -1,3 +0,0 @@
|
||||||
#include "ecs/entity.h"
|
|
||||||
|
|
||||||
uint32_t simpleengine::Entity::incrementing_handle = 0;
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include "entity_manager.h"
|
|
||||||
|
|
||||||
simpleengine::EntityManager::EntityManager() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::EntityManager::submit_entity(std::shared_ptr<simpleengine::Entity> entity) {
|
|
||||||
entities.emplace(entity->get_handle(), entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool simpleengine::EntityManager::withdraw_entity(std::shared_ptr<simpleengine::Entity> entity) {
|
|
||||||
auto it = entities.find(entity->get_handle());
|
|
||||||
|
|
||||||
if (it != entities.end()) {
|
|
||||||
it->second->destroy();
|
|
||||||
entities.erase(it);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::EntityManager::initialize() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::EntityManager::destroy() {
|
|
||||||
std::cout << "Destroy entity manager!" << std::endl;
|
|
||||||
|
|
||||||
for (auto& [handle, entity] : entities) {
|
|
||||||
entity->destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void simpleengine::EntityManager::update(const float& delta_time) {
|
|
||||||
for (auto& [handle, entity] : entities) {
|
|
||||||
entity->update(delta_time);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,15 +14,26 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
Model::Model(std::string file_path) {
|
Model::Model(std::string file_path, int model_processing_flags, int assimp_flags): model_processing_flags(model_processing_flags),
|
||||||
|
additional_assimp_flags(assimp_flags) {
|
||||||
load_model(file_path);
|
load_model(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::post_process() {
|
||||||
|
if (model_processing_flags & ModelProcessingFlags::MdlProcFlag_FLIP_TEX_COORDS_VERTICALLY) {
|
||||||
|
vertically_flip_tex_coords();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model_processing_flags & ModelProcessingFlags::MdlProcFlag_FLIP_TEX_COORDS_HORIZONTALLY) {
|
||||||
|
horizontally_flip_tex_coords();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Model::load_model(std::string path) {
|
void Model::load_model(std::string path) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
// assimp post processing options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
// assimp post processing options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
||||||
const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
|
const aiScene *scene = importer.ReadFile(path, additional_assimp_flags | aiProcess_Triangulate | aiProcess_FlipUVs);
|
||||||
|
|
||||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
||||||
std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
|
std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
|
||||||
|
@ -31,28 +42,30 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
model_directory = path.substr(0, path.find_last_of('/'));
|
model_directory = path.substr(0, path.find_last_of('/'));
|
||||||
|
|
||||||
process_node(scene->mRootNode, scene);
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> processed_textures;
|
||||||
|
process_node(processed_textures, scene->mRootNode, scene);
|
||||||
|
|
||||||
|
post_process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::process_node(aiNode* node, const aiScene* scene) {
|
void Model::process_node(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiNode* node, const aiScene* scene) {
|
||||||
// process all the node's meshes (if any)
|
// process all the node's meshes (if any)
|
||||||
for (int i = 0; i < node->mNumMeshes; i++) {
|
for (int i = 0; i < node->mNumMeshes; i++) {
|
||||||
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
|
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
meshes.push_back(process_mesh(mesh, scene));
|
meshes.push_back(process_mesh(processed_textures, mesh, scene));
|
||||||
}
|
}
|
||||||
|
|
||||||
// then do the same for each of its children
|
// then do the same for each of its children
|
||||||
for (int i = 0; i < node->mNumChildren; i++) {
|
for (int i = 0; i < node->mNumChildren; i++) {
|
||||||
process_node(node->mChildren[i], scene);
|
process_node(processed_textures, node->mChildren[i], scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Mesh Model::process_mesh(aiMesh* mesh, const aiScene* scene) {
|
gfx::Mesh Model::process_mesh(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMesh* mesh, const aiScene* scene) {
|
||||||
std::vector<LitVertex> vertices;
|
std::vector<LitVertex> vertices;
|
||||||
std::vector<unsigned int> indices;
|
std::vector<unsigned int> indices;
|
||||||
std::vector<Texture> textures;
|
|
||||||
|
|
||||||
for(unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
|
||||||
LitVertex vertex;
|
LitVertex vertex;
|
||||||
vertex.color = glm::vec3(1.f);
|
vertex.color = glm::vec3(1.f);
|
||||||
vertex.texture_id = 0;
|
vertex.texture_id = 0;
|
||||||
|
@ -60,10 +73,12 @@ namespace simpleengine::gfx {
|
||||||
simpleengine::Vectorf position(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
|
simpleengine::Vectorf position(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
|
||||||
vertex.position = position;
|
vertex.position = position;
|
||||||
|
|
||||||
glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
|
if (mesh->HasNormals()) {
|
||||||
vertex.normal = normal;
|
glm::vec3 normal(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
|
||||||
|
vertex.normal = normal;
|
||||||
|
}
|
||||||
|
|
||||||
if(mesh->mTextureCoords[0]) {
|
if (mesh->mTextureCoords[0]) {
|
||||||
glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
|
glm::vec2 tex_coord(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
|
||||||
|
|
||||||
vertex.tex_coord = tex_coord;
|
vertex.tex_coord = tex_coord;
|
||||||
|
@ -83,18 +98,18 @@ namespace simpleengine::gfx {
|
||||||
|
|
||||||
// Create a default material and white texture.
|
// Create a default material and white texture.
|
||||||
auto white_texture = gfx::Texture::white_texture();
|
auto white_texture = gfx::Texture::white_texture();
|
||||||
std::unordered_map<aiTextureType, std::vector<Texture>> default_textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> default_textures;
|
||||||
default_textures.emplace(white_texture.type, std::vector<Texture>{ white_texture });
|
default_textures.emplace(white_texture.type, std::vector<std::shared_ptr<Texture>>{ std::make_shared<Texture>(white_texture) });
|
||||||
gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
gfx::Material mat(default_textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||||
|
|
||||||
if(mesh->mMaterialIndex >= 0) {
|
if (mesh->mMaterialIndex >= 0) {
|
||||||
std::cout << "TODO: Process model materials!" << std::endl;
|
std::cout << "TODO: Process model materials!" << std::endl;
|
||||||
|
|
||||||
std::unordered_map<aiTextureType, std::vector<Texture>> textures;
|
std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>> textures;
|
||||||
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||||
|
|
||||||
// Load Diffuse texture maps
|
// Load Diffuse texture maps
|
||||||
std::vector<Texture> diffuse_maps = load_material_textures(material, aiTextureType_DIFFUSE);
|
std::vector<std::shared_ptr<Texture>> diffuse_maps = load_material_texture(processed_textures, material, aiTextureType_DIFFUSE);
|
||||||
if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps);
|
if (!diffuse_maps.empty()) textures.emplace(aiTextureType_DIFFUSE, diffuse_maps);
|
||||||
|
|
||||||
// TODO Handle other types of texture maps
|
// TODO Handle other types of texture maps
|
||||||
|
@ -102,27 +117,97 @@ namespace simpleengine::gfx {
|
||||||
if (!textures.empty()) {
|
if (!textures.empty()) {
|
||||||
// TODO: Find a way to let the user set the scalars.
|
// TODO: Find a way to let the user set the scalars.
|
||||||
mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
mat = Material(textures, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
// Add `textures` into the `processed_textures` list.
|
||||||
|
for (const auto& pair : textures) {
|
||||||
|
for (const auto& texture : pair.second) {
|
||||||
|
bool contains = false;
|
||||||
|
|
||||||
|
auto found = processed_textures.find(pair.first);
|
||||||
|
if (found != processed_textures.end()) {
|
||||||
|
for (const auto& processed_text : found->second) {
|
||||||
|
if (processed_text->path == texture->path) {
|
||||||
|
contains = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contains) {
|
||||||
|
//found->second
|
||||||
|
found->second.emplace_back(texture);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processed_textures.emplace(pair.first, std::vector<std::shared_ptr<Texture>>{ pair.second });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mesh(vertices, indices, mat);
|
Mesh se_mesh(vertices, indices, mat);
|
||||||
|
|
||||||
|
if (!mesh->HasNormals()) {
|
||||||
|
se_mesh.calculate_normals();
|
||||||
|
}
|
||||||
|
|
||||||
|
return se_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Texture> Model::load_material_textures(aiMaterial* material, aiTextureType type) {
|
std::unordered_map<aiTextureType, std::vector<Texture>> load_all_textures(aiMaterial* material) {
|
||||||
std::vector<Texture> textures;
|
// Load Diffuse texture maps
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < material->GetTextureCount(type); i++) {
|
std::vector<std::shared_ptr<Texture>> Model::load_material_texture(std::unordered_map<aiTextureType, std::vector<std::shared_ptr<Texture>>>& processed_textures, aiMaterial* material, aiTextureType type) {
|
||||||
aiString texture_path;
|
std::vector<std::shared_ptr<Texture>> textures;
|
||||||
material->GetTexture(type, i, &texture_path);
|
|
||||||
|
for (int i = 0; i < material->GetTextureCount(type); i++) {
|
||||||
|
aiString texture_path_ai;
|
||||||
|
material->GetTexture(type, i, &texture_path_ai);
|
||||||
|
std::string texture_path = texture_path_ai.C_Str();
|
||||||
|
|
||||||
|
// If the texture has been read, we should skip it.
|
||||||
|
bool skip = false;
|
||||||
|
for (const auto& pair : processed_textures) {
|
||||||
|
if (pair.first == type) {
|
||||||
|
for (const auto& texture : pair.second) {
|
||||||
|
if (texture->path == texture_path) {
|
||||||
|
textures.emplace_back(texture); // Push a copy of the texture for this Mesh.
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (skip) continue;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << model_directory << "/" << texture_path.C_Str();
|
ss << model_directory << "/" << texture_path;
|
||||||
std::string full_path = ss.str();
|
std::string full_path = ss.str();
|
||||||
|
|
||||||
Texture texture(full_path.c_str(), type);
|
Texture texture(full_path.c_str(), type, /* TextureFlags::TexFlags_FLIP_VERTICALLY | */ TextureFlags::TexFlags_IMG_2D | TextureFlags::TexFlags_MIPMAP);
|
||||||
textures.emplace_back(texture);
|
texture.path = texture_path;
|
||||||
|
textures.emplace_back(std::make_shared<Texture>(texture));
|
||||||
|
|
||||||
|
std::cout << "Texture full path: " << full_path << ", texture_path: " << texture_path << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return textures;
|
return textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Model::vertically_flip_tex_coords() {
|
||||||
|
for (auto& mesh : meshes) {
|
||||||
|
for (auto& vertex : mesh.vertices) {
|
||||||
|
vertex.tex_coord.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::horizontally_flip_tex_coords() {
|
||||||
|
for (auto& mesh : meshes) {
|
||||||
|
for (auto& vertex : mesh.vertices) {
|
||||||
|
vertex.tex_coord.x *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace simpleengine::gfx
|
} // namespace simpleengine::gfx
|
|
@ -1,6 +1,4 @@
|
||||||
#include "gfx/renderer.h"
|
#include "gfx/renderer.h"
|
||||||
#include "ecs/component/component.h"
|
|
||||||
#include "ecs/entity.h"
|
|
||||||
#include "gfx/mesh.h"
|
#include "gfx/mesh.h"
|
||||||
#include "gfx/vao.h"
|
#include "gfx/vao.h"
|
||||||
#include "renderable.h"
|
#include "renderable.h"
|
||||||
|
@ -12,16 +10,7 @@
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
void create_mesh_buffers(std::shared_ptr<simpleengine::Component> comp, simpleengine::gfx::Mesh& mesh);
|
void create_mesh_buffers(simpleengine::gfx::Mesh& mesh);
|
||||||
|
|
||||||
void Renderer::RenderingModel::destroy_buffers() {
|
|
||||||
std::cout << "Destroying entity models..." << std::endl;
|
|
||||||
|
|
||||||
// Iterate through all buffer lists and destroy each inner buffer.
|
|
||||||
for (auto& pair : component_models) {
|
|
||||||
pair.second.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) {
|
Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) {
|
||||||
|
|
||||||
|
@ -45,24 +34,40 @@ namespace simpleengine::gfx {
|
||||||
glDebugMessageCallback(debug_message_callback, 0);
|
glDebugMessageCallback(debug_message_callback, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::submit_entity(std::shared_ptr<simpleengine::Entity> entity) {
|
void Renderer::queue_job(RenderingJob job) {
|
||||||
std::cout << "Submitting entity (" << entity->get_handle() << ")..." << std::endl;
|
RenderingJob& emplace = rendering_queue.emplace(job);
|
||||||
auto it = rendering_models.emplace(entity->get_handle(), entity);
|
create_job_buffers(emplace);
|
||||||
it.first->second.update_buffers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::withdraw_entity(std::shared_ptr<simpleengine::Entity> entity) {
|
void Renderer::create_job_buffers(RenderingJob& job) {
|
||||||
std::cout << "Withdrawing entity (" << entity->get_handle() << ")...";
|
Mesh& rendering_mesh = job.rendering_mesh;
|
||||||
auto it = rendering_models.find(entity->get_handle());
|
|
||||||
|
|
||||||
if (it != rendering_models.end()) {
|
if (!rendering_mesh.are_buffers_created) {
|
||||||
it->second.destroy_buffers();
|
gfx::VBO& vbo = rendering_mesh.vbo;
|
||||||
rendering_models.erase(it);
|
gfx::VBO& ebo = rendering_mesh.ebo;
|
||||||
|
gfx::VAO& vao = rendering_mesh.vao;
|
||||||
|
|
||||||
return true;
|
vao.bind();
|
||||||
|
vbo.buffer(rendering_mesh.vertices.data(), 0, sizeof(LitVertex) * rendering_mesh.vertices.size());
|
||||||
|
|
||||||
|
if (!rendering_mesh.indicies.empty()) {
|
||||||
|
ebo.buffer(rendering_mesh.indicies.data(), 0, rendering_mesh.indicies.size() * sizeof(GLuint));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable VAO attributes
|
||||||
|
vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false);
|
||||||
|
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false);
|
||||||
|
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false);
|
||||||
|
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false);
|
||||||
|
vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
rendering_mesh.are_buffers_created = true;
|
||||||
|
|
||||||
|
std::cout << "Created render job buffers" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::update(const float& delta_time) {
|
void Renderer::update(const float& delta_time) {
|
||||||
|
@ -76,113 +81,53 @@ namespace simpleengine::gfx {
|
||||||
void Renderer::destroy() {
|
void Renderer::destroy() {
|
||||||
std::cout << "Destroying renderer..." << std::endl;
|
std::cout << "Destroying renderer..." << std::endl;
|
||||||
|
|
||||||
for (auto& [handle, rendering] : rendering_models) {
|
/* for (auto& [handle, rendering] : rendering_models) {
|
||||||
rendering.destroy_buffers();
|
rendering.destroy_buffers();
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::render() {
|
void Renderer::render() {
|
||||||
shader.use();
|
shader.use();
|
||||||
|
|
||||||
for (auto& [handle, rendering] : rendering_models) {
|
while (!rendering_queue.empty()) {
|
||||||
if (rendering.component_models.size() >= 0) {
|
// Get the job from the queue, we'll remove it after we render.
|
||||||
std::shared_ptr<Entity>& entity = rendering.entity;
|
RenderingJob& job = rendering_queue.front();
|
||||||
|
Mesh& mesh = job.rendering_mesh;
|
||||||
|
|
||||||
shader.set_uniform_matrix_4f("transform_matrix", entity->transform_matrix, false);
|
shader.set_uniform_matrix_4f("transform_matrix", job.transform_mat, false);
|
||||||
|
|
||||||
for (const auto& pair : rendering.component_models) {
|
std::optional<Material>& material = mesh.material;
|
||||||
Mesh& model = pair.second;
|
|
||||||
std::optional<Material>& material = model.material;
|
|
||||||
|
|
||||||
shader.set_uniform_int("u_textures", 0, false);
|
shader.set_uniform_int("u_textures", 0, false);
|
||||||
|
|
||||||
if (material.has_value()) {
|
if (material.has_value()) {
|
||||||
shader.set_uniform_float("u_texture_shine", material->shine, false);
|
shader.set_uniform_float("u_texture_shine", material->shine, false);
|
||||||
shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false);
|
shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false);
|
||||||
|
|
||||||
int texture_count = 0;
|
int texture_count = 0;
|
||||||
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
|
auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE);
|
||||||
for (const auto& texture : diffuse_maps->second) {
|
for (const auto& texture : diffuse_maps->second) {
|
||||||
// We can only bind to 16 textures at a time (indexes are 0-15)
|
// We can only bind to 16 textures at a time (indexes are 0-15)
|
||||||
if (texture_count >= 16) break;
|
if (texture_count >= 16) break;
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + texture_count);
|
glActiveTexture(GL_TEXTURE0 + texture_count);
|
||||||
glBindTextureUnit(texture_count, texture.get_texture_id());
|
glBindTextureUnit(texture_count, texture->get_texture_id());
|
||||||
|
|
||||||
texture_count++;
|
texture_count++;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model.vao.bind();
|
|
||||||
if (model.indicies.empty()) {
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, model.vertices.size());
|
|
||||||
} else {
|
|
||||||
glDrawElements(GL_TRIANGLES, model.indicies.size(), GL_UNSIGNED_INT, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mesh.vao.bind();
|
||||||
|
if (mesh.indicies.empty()) {
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size());
|
||||||
|
} else {
|
||||||
|
glDrawElements(GL_TRIANGLES, mesh.indicies.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we'll remove the job from the queue.
|
||||||
|
rendering_queue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.unuse();
|
shader.unuse();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::RenderingModel::update_buffers() {
|
|
||||||
if (entity->has_component<simpleengine::MeshComponent>()) {
|
|
||||||
std::shared_ptr<MeshComponent> comp = entity->get_component<simpleengine::MeshComponent>();
|
|
||||||
auto iter = component_models.find(comp->get_handle());
|
|
||||||
if (iter == component_models.end()) {
|
|
||||||
std::cout << "Enabling buffer attributes for MeshComponent (" << comp->get_handle() << ")..." << std::endl;
|
|
||||||
|
|
||||||
//iter->second = comp->model;
|
|
||||||
gfx::Mesh& mesh = comp->model;
|
|
||||||
create_mesh_buffers(comp, mesh);
|
|
||||||
component_models.emplace(comp->get_handle(), mesh);
|
|
||||||
|
|
||||||
std::cout << "Enabled all buffer attributes for MeshComponent" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "Already exists" << std::endl;
|
|
||||||
}
|
|
||||||
} else if (entity->has_component<simpleengine::ModelComponent>()) {
|
|
||||||
std::shared_ptr<ModelComponent> comp = entity->get_component<simpleengine::ModelComponent>();
|
|
||||||
|
|
||||||
auto iter = component_models.find(comp->get_handle());
|
|
||||||
if (iter == component_models.end()) {
|
|
||||||
std::cout << "Enabling buffer attributes for ModelComponent (" << comp->get_handle() << ")..." << std::endl;
|
|
||||||
|
|
||||||
// Store all the model's meshes
|
|
||||||
for (auto& mesh : comp->model.meshes) {
|
|
||||||
create_mesh_buffers(comp, mesh);
|
|
||||||
|
|
||||||
component_models.emplace(comp->get_handle(), mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Enabled all buffer attributes for ModelComponent" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "Already exists" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void create_mesh_buffers(std::shared_ptr<Component> comp, gfx::Mesh& mesh) {
|
|
||||||
gfx::VBO& vbo = mesh.vbo;
|
|
||||||
gfx::VBO& ebo = mesh.ebo;
|
|
||||||
gfx::VAO& vao = mesh.vao;
|
|
||||||
|
|
||||||
vao.bind();
|
|
||||||
vbo.buffer(mesh.vertices.data(), 0, sizeof(LitVertex) * mesh.vertices.size());
|
|
||||||
|
|
||||||
if (!mesh.indicies.empty()) {
|
|
||||||
ebo.buffer(mesh.indicies.data(), 0, mesh.indicies.size() * sizeof(GLuint));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable VAO attributes
|
|
||||||
vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false);
|
|
||||||
vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false);
|
|
||||||
vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false);
|
|
||||||
vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false);
|
|
||||||
vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -4,7 +4,11 @@
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
|
|
||||||
namespace simpleengine::gfx {
|
namespace simpleengine::gfx {
|
||||||
Texture::Texture(const char* path, aiTextureType type, bool img_2d, bool mipmap): type(type) {
|
Texture::Texture(const char* path, aiTextureType type, int flags): type(type), path(path) {
|
||||||
|
bool img_2d = flags & TextureFlags::TexFlags_IMG_2D;
|
||||||
|
bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY;
|
||||||
|
bool mipmap = flags & TextureFlags::TexFlags_MIPMAP;
|
||||||
|
|
||||||
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
||||||
|
|
||||||
glGenTextures(1, &texture_id);
|
glGenTextures(1, &texture_id);
|
||||||
|
@ -17,7 +21,9 @@ namespace simpleengine::gfx {
|
||||||
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
||||||
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
||||||
|
|
||||||
// Read 4 channels (RGBA)
|
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||||
|
|
||||||
|
// Read 4 channels (RGBA)
|
||||||
img_data = stbi_load(path, &width, &height, &channels, 4);
|
img_data = stbi_load(path, &width, &height, &channels, 4);
|
||||||
if(!img_data) {
|
if(!img_data) {
|
||||||
const char* failure = stbi_failure_reason();
|
const char* failure = stbi_failure_reason();
|
||||||
|
@ -32,10 +38,16 @@ namespace simpleengine::gfx {
|
||||||
glGenerateMipmap(image_type_gl);
|
glGenerateMipmap(image_type_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, bool img_2d, bool mipmap): type(type) {
|
Texture::Texture(const unsigned char *const buffer, int buffer_length, aiTextureType type, int flags): type(type) {
|
||||||
|
bool img_2d = flags & TextureFlags::TexFlags_IMG_2D;
|
||||||
|
bool flip_vertically = flags & TextureFlags::TexFlags_FLIP_VERTICALLY;
|
||||||
|
bool mipmap = flags & TextureFlags::TexFlags_MIPMAP;
|
||||||
|
|
||||||
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
image_type_gl = img_2d ? GL_TEXTURE_2D : GL_TEXTURE_3D;
|
||||||
|
|
||||||
glGenTextures(1, &texture_id);
|
glGenTextures(1, &texture_id);
|
||||||
|
@ -48,6 +60,8 @@ namespace simpleengine::gfx {
|
||||||
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
glTexParameteri(image_type_gl, GL_TEXTURE_MIN_FILTER, linear_param);
|
||||||
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
glTexParameteri(image_type_gl, GL_TEXTURE_MAG_FILTER, linear_param);
|
||||||
|
|
||||||
|
stbi_set_flip_vertically_on_load(flip_vertically);
|
||||||
|
|
||||||
// Read 4 channels (RGBA)
|
// Read 4 channels (RGBA)
|
||||||
img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4);
|
img_data = stbi_load_from_memory(buffer, buffer_length, &width, &height, &channels, 4);
|
||||||
if(!img_data) {
|
if(!img_data) {
|
||||||
|
@ -63,11 +77,13 @@ namespace simpleengine::gfx {
|
||||||
glGenerateMipmap(image_type_gl);
|
glGenerateMipmap(image_type_gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::Texture(std::vector<unsigned char> buffer, aiTextureType type, bool img_2d, bool mipmap) :
|
Texture::Texture(std::vector<unsigned char> buffer, aiTextureType type, int flags) :
|
||||||
Texture(buffer.data(), buffer.size(), type, img_2d, mipmap) {
|
Texture(buffer.data(), buffer.size(), type, flags) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "scene.h"
|
||||||
|
#include "ecs/component/mesh_component.h"
|
||||||
|
#include "ecs/component/model_component.h"
|
||||||
|
#include "ecs/component/transform_component.h"
|
||||||
|
#include "ecs/component/rotating_component.h"
|
||||||
|
#include "ecs/entity.h"
|
||||||
|
#include "gfx/renderer.h"
|
||||||
|
|
||||||
|
namespace simpleengine {
|
||||||
|
Scene::Scene(std::shared_ptr<gfx::Renderer> renderer) : renderer(renderer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ecs::Entity Scene::create_entity() {
|
||||||
|
return ecs::Entity(registry, registry.create());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::update(const float& delta_time) {
|
||||||
|
// Is there a way these can be grouped?
|
||||||
|
registry.view<const TransformComponent, ModelComponent>().each([this](const TransformComponent& transform, ModelComponent& model_component) {
|
||||||
|
for (auto& mesh : model_component.model.meshes) {
|
||||||
|
renderer->queue_job(gfx::RenderingJob(mesh, transform.transform_matrix));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.view<const TransformComponent, MeshComponent>().each([this](const TransformComponent& transform, MeshComponent& mesh_component) {
|
||||||
|
renderer->queue_job(gfx::RenderingJob(mesh_component.mesh, transform.transform_matrix));
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
|
||||||
|
transform.rotate(rotating.rate * delta_time, rotating.rotation_axis);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue