Make scene loading part of gltf loader

This commit is contained in:
2022-10-22 23:26:34 +02:00
parent 43e25b2628
commit a3b6c3b346
14 changed files with 306 additions and 473 deletions

View File

@@ -3,7 +3,7 @@ add_library(fever_engine
Controller.cpp
Window.cpp
Light.cpp
Scene.cpp
scene.cpp
FrameBuffer.cpp
Helper.cpp
util/Log.cpp

View File

@@ -23,29 +23,34 @@
using namespace entt::literals;
Controller::Controller()
: m_scene(m_shader_cache),
m_gameWindow(std::make_shared<Window>()),
: m_gameWindow(std::make_shared<Window>()),
m_postProcessFrameBuffer(m_gameWindow->dimensions().first,
m_gameWindow->dimensions().second,
post_processing_shader)
post_processing_shader),
m_gltf_loader{.image_cache = m_image_cache,
.material_cache = m_material_cache,
.mesh_cache = m_mesh_cache,
.shader_cache = m_shader_cache,
.scene_cache = m_scene_cache,
.gltf_mesh_cache = m_gltf_mesh_cache,
.gltf_node_cache = m_gltf_node_cache},
m_gltf_cache(m_gltf_loader)
{
// if (!gltf.cameras.empty()) {
// auto const &gltf_camera = gltf.cameras.at(0);
// std::filesystem::path document_path("Lantern/glTF-Binary/Lantern.glb");
std::filesystem::path document_path("ABeautifulGame.glb");
entt::hashed_string document_hash(document_path.c_str());
// assert(gltf_camera.type == fx::gltf::Camera::Type::Perspective);
// auto const &perspective = gltf_camera.perspective;
entt::resource<Gltf> gltf_document =
m_gltf_cache.load(document_hash, document_path).first->second;
// m_camera = std::make_shared<Camera>(perspective.yfov, perspective.aspectRatio);
// } else {
// m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio());
// }
m_scene = gltf_document->default_scene.value().handle();
}
void Controller::run()
{
updateExposure(post_processing_shader);
entt::hashed_string shader_hash (Material::SHADER_NAME.data());
entt::hashed_string shader_hash(Material::SHADER_NAME.data());
auto standard_material_shader =
m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
@@ -74,7 +79,7 @@ void Controller::run()
auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
static constexpr auto MICROSECONDS_PER_SECOND = 1'000'000;
m_scene.update(
m_scene->update(
std::chrono::microseconds(static_cast<unsigned>(m_deltaTime * MICROSECONDS_PER_SECOND)),
key_input,
mouse_cursor_input,
@@ -87,7 +92,7 @@ void Controller::run()
m_postProcessFrameBuffer.bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Render::render(m_scene.registry());
Render::render(m_scene->registry());
Framebuffer::unbind();
m_postProcessFrameBuffer.drawOnEntireScreen();

View File

@@ -1,14 +1,15 @@
#pragma once
#include "FrameBuffer.h"
#include "Scene.h"
#include "scene.h"
#include "shader.h"
#include "gltf_loader.h"
#include <entt/entt.hpp>
#include <glm/glm.hpp>
#include <memory>
#include <unordered_map>
#include <vector>
#include <entt/entt.hpp>
class Window;
class Scene;
@@ -29,18 +30,28 @@ private:
void update_window_dimensions();
std::shared_ptr<Window> m_gameWindow;
Shader skybox_shader{"skybox", "data/shaders"};
Shader post_processing_shader{"post_processing", "data/shaders"};
Framebuffer m_postProcessFrameBuffer;
entt::resource_cache<Shader, ShaderLoader> m_shader_cache;
static constexpr unsigned MAX_FPS = 60;
Scene m_scene;
std::shared_ptr<Scene> m_scene;
double m_deltaTime{};
float m_exposure = 1.0;
// Resource caches
entt::resource_cache<Image> m_image_cache;
entt::resource_cache<Material> m_material_cache;
entt::resource_cache<Mesh> m_mesh_cache;
entt::resource_cache<Scene> m_scene_cache;
entt::resource_cache<Shader, ShaderLoader> m_shader_cache;
entt::resource_cache<GltfMesh> m_gltf_mesh_cache;
entt::resource_cache<GltfNode> m_gltf_node_cache;
GltfLoader m_gltf_loader;
entt::resource_cache<Gltf, GltfLoader> m_gltf_cache;
};

View File

@@ -1,148 +0,0 @@
#include "Scene.h"
#include "camera.h"
#include "mesh.h"
#include "name.h"
#include "relationship.h"
#include "shader.h"
#include "transform.h"
#include "util/Log.h"
using namespace entt::literals;
// TODO: make scene initialization part of gltf loader as seen in bevy
Scene::Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache)
{
GltfLoader loader{.image_cache = m_image_cache,
.material_cache = m_material_cache,
.mesh_cache = m_mesh_cache,
.shader_cache = shader_cache,
.gltf_mesh_cache = m_gltf_mesh_cache,
.gltf_node_cache = m_gltf_node_cache,
.gltf_scene_cache = m_gltf_scene_cache};
entt::resource_cache<Gltf, GltfLoader> gltf_resource_cache{loader};
std::filesystem::path document_path("ABeautifulGame.glb");
// std::filesystem::path document_path("Lantern/glTF-Binary/Lantern.glb");
entt::hashed_string document_hash(document_path.c_str());
entt::resource<Gltf> gltf_document =
gltf_resource_cache.load(document_hash, document_path).first->second;
auto default_scene = gltf_document->default_scene;
// Spawn an entity for every node in scene
for (auto const &node : default_scene->nodes) {
std::function<entt::entity(GltfNode const &, std::optional<entt::entity>)> spawn_node =
[this, &spawn_node](GltfNode const &node, std::optional<entt::entity> parent) {
auto entity = m_registry.create();
m_registry.emplace<Name>(entity, node.name);
m_registry.emplace<Transform>(entity, node.transform);
m_registry.emplace<GlobalTransform>(entity, GlobalTransform{});
if (parent.has_value()) {
m_registry.emplace<Parent>(entity, Parent{.parent = parent.value()});
}
std::vector<entt::entity> child_entities;
auto mesh = node.mesh;
if (mesh.has_value()) {
for (auto const &primitive : mesh.value()->primitives) {
auto mesh_entity = m_registry.create();
m_registry.emplace<Parent>(mesh_entity, Parent{.parent = entity});
m_registry.emplace<Transform>(mesh_entity, Transform{});
m_registry.emplace<GlobalTransform>(mesh_entity, GlobalTransform{});
m_registry.emplace<entt::resource<Mesh>>(mesh_entity, primitive.mesh);
m_registry.emplace<entt::resource<Material>>(mesh_entity,
primitive.material);
child_entities.push_back(mesh_entity);
}
}
// Spawn child nodes
for (auto const &child : node.children) {
auto child_entity = spawn_node(child, entity);
child_entities.push_back(child_entity);
}
m_registry.emplace<Children>(entity, Children{.children = child_entities});
return entity;
};
spawn_node(node, {});
}
auto mesh_view = m_registry.view<entt::resource<Mesh>>();
for (auto [entity, mesh] : mesh_view.each()) {
m_registry.emplace<GpuMesh>(entity, GpuMesh(mesh));
// Remove Mesh resource as it is no longer needed.
m_registry.erase<entt::resource<Mesh>>(entity);
}
auto material_view = m_registry.view<entt::resource<Material>>();
for (auto [entity, material] : material_view.each()) {
m_registry.emplace<GpuMaterial>(entity, GpuMaterial(material));
// Remove Material resource as it is no longer needed.
m_registry.erase<entt::resource<Material>>(entity);
}
// Spawn the camera
auto entity = m_registry.create();
m_registry.emplace<Name>(entity, "Camera");
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.25, -1.0)});
m_registry.emplace<GlobalTransform>(entity, GlobalTransform{});
m_registry.emplace<Camera>(entity, Camera{.projection = Camera::Perspective{}});
}
void Scene::update(std::chrono::duration<float> delta,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio,
bool cursor_catched)
{
{
// Update GlobalTransform components
// TODO: Only do this when the Transform changed.
auto root_transform_view =
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
global_transform = transform;
auto parent_global_transform = global_transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
std::function<void(entt::entity entity,
GlobalTransform parent_global_transform)>
transform_propagate = [this, &transform_propagate, &transform_view](
entt::entity entity,
GlobalTransform parent_global_transform) {
auto [transform, global_transform, parent] = transform_view.get(entity);
global_transform.transform = parent_global_transform.transform *
GlobalTransform(transform).transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
transform_propagate(child, global_transform);
}
}
};
transform_propagate(child, parent_global_transform);
}
}
}
}
Camera::aspect_ratio_update(m_registry, aspect_ratio);
Camera::keyboard_movement(m_registry, key_input, delta);
if (cursor_catched) {
Camera::mouse_orientation(m_registry, mouse_cursor_input);
}
}

View File

@@ -1,36 +0,0 @@
#pragma once
#include "Window.h"
#include "gltf_loader.h"
#include "material.h"
#include "mesh.h"
#include <chrono>
#include <entt/entt.hpp>
class Shader;
class Scene
{
public:
Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache);
void update(std::chrono::duration<float> delta_time,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio,
bool cursor_catched);
auto registry() -> entt::registry & { return m_registry; }
private:
entt::registry m_registry;
// Resource caches
entt::resource_cache<Image> m_image_cache;
entt::resource_cache<Material> m_material_cache;
entt::resource_cache<Mesh> m_mesh_cache;
entt::resource_cache<GltfMesh> m_gltf_mesh_cache;
entt::resource_cache<GltfNode> m_gltf_node_cache;
entt::resource_cache<GltfScene> m_gltf_scene_cache; // May be moved out of Scene
};

View File

@@ -1,162 +0,0 @@
#include "ShaderProgram.h"
#include "util/Log.h"
#include <fmt/format.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreateProgram())
{
std::string vertexShaderSource = parse(prototype.vertexPath);
std::string fragmentShaderSource = parse(prototype.fragmentPath);
GLuint vertexShader = compile(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(m_shaderProgramId, vertexShader);
glAttachShader(m_shaderProgramId, fragmentShader);
glLinkProgram(m_shaderProgramId);
GLint isLinked = 0;
glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked);
if (isLinked == 0) {
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")",
prototype.vertexPath,
prototype.fragmentPath);
}
#ifdef NDEBUG
glDetachShader(m_shaderProgramId, vertexShader);
glDetachShader(m_shaderProgramId, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
#endif
Log::logger().trace(R"(Loaded shaderprogram "{}".)", prototype.name);
}
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(m_shaderProgramId);
}
void ShaderProgram::bind() const
{
glUseProgram(m_shaderProgramId);
}
void ShaderProgram::unbind()
{
glUseProgram(0);
}
auto ShaderProgram::parse(const std::filesystem::path &path) -> std::string
{
std::fstream file;
file.open(path, std::ios::in);
if (!file.is_open()) {
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
std::terminate();
}
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
}
auto ShaderProgram::compile(const std::string &shaderSource, GLenum type) -> GLuint
{
GLuint shaderId = glCreateShader(type);
const char *src = shaderSource.c_str();
glShaderSource(shaderId, 1, &src, nullptr);
glCompileShader(shaderId);
int result{};
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result);
if (result != GL_TRUE) {
int length{};
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length);
std::string message;
message.reserve(static_cast<unsigned>(length));
glGetShaderInfoLog(shaderId, length, &length, message.data());
Log::logger().error("Shader compilation failed: {}", message);
return 0;
}
return shaderId;
}
auto ShaderProgram::retrieveUniformLocation(std::string_view uniform_name) const -> GLint
{
if (m_uniformLocationCache.find(uniform_name.data()) != m_uniformLocationCache.end()) {
return m_uniformLocationCache[uniform_name.data()];
}
GLint location = glGetUniformLocation(m_shaderProgramId, uniform_name.data());
if (location != -1) {
m_uniformLocationCache[uniform_name.data()] = location;
} else {
Log::logger().warn(R"(Uniform "{}" not found.)", uniform_name);
}
return location;
}
void ShaderProgram::set_uniform(const std::string &name, bool value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1i(location, (int)value);
}
void ShaderProgram::set_uniform(const std::string &name, int value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1i(location, value);
}
void ShaderProgram::set_uniform(const std::string &name, unsigned int value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1ui(location, value);
}
void ShaderProgram::set_uniform(const std::string &name, float value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1f(location, value);
}
void ShaderProgram::set_uniform(const std::string &name, glm::vec2 vector) const
{
GLint location = retrieveUniformLocation(name);
glUniform2f(location, vector.x, vector.y);
}
void ShaderProgram::set_uniform(const std::string &name, glm::vec3 vector) const
{
GLint location = retrieveUniformLocation(name);
glUniform3f(location, vector.x, vector.y, vector.z);
}
void ShaderProgram::set_uniform(const std::string &name, glm::mat3 matrix) const
{
GLint location = retrieveUniformLocation(name);
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
}
void ShaderProgram::set_uniform(const std::string &name, glm::mat4 matrix) const
{
GLint location = retrieveUniformLocation(name);
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
}
auto ShaderProgram::getShaderProgramId() const -> GLuint
{
return m_shaderProgramId;
}

View File

@@ -1,46 +0,0 @@
#pragma once
#include <filesystem>
#include <glad/gl.h>
#include <glm/glm.hpp>
#include <optional>
#include <string>
#include <unordered_map>
class ShaderProgram
{
public:
struct Prototype
{
std::string name;
std::string vertexPath;
std::string fragmentPath;
};
ShaderProgram(Prototype prototype);
~ShaderProgram();
void bind() const;
static void unbind();
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
// May be rewritten...
void set_uniform(const std::string &name, bool value) const;
void set_uniform(const std::string &name, int value) const;
void set_uniform(const std::string &name, unsigned int value) const;
void set_uniform(const std::string &name, float value) const;
void set_uniform(const std::string &name, glm::vec2 vector) const;
void set_uniform(const std::string &name, glm::vec3 vector) const;
void set_uniform(const std::string &name, glm::mat3 matrix) const;
void set_uniform(const std::string &name, glm::mat4 matrix) const;
auto getShaderProgramId() const -> GLuint;
private:
static auto parse(const std::filesystem::path &path) -> std::string;
static auto compile(const std::string &shaderSource, GLenum type) -> GLuint;
GLuint m_shaderProgramId;
mutable std::unordered_map<std::string, GLint> m_uniformLocationCache;
};

View File

@@ -20,6 +20,8 @@ struct Camera
static constexpr float SPEED = 0.5;
static constexpr float ACCELERATION = 5.0;
static constexpr glm::vec3 DEFAULT_POSITION = glm::vec3(0.0, 0.25, -1.0);
struct Perspective
{
float fov = DEFAULT_FOV;

51
src/gltf.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include "material.h"
#include "mesh.h"
#include "transform.h"
#include <entt/entt.hpp>
#include <fx/gltf.h>
#include <optional>
#include <vector>
class Mesh;
class Scene;
class Material;
class Image;
struct GltfPrimitive
{
entt::resource<Mesh> mesh;
entt::resource<Material> material;
};
struct GltfMesh
{
std::vector<GltfPrimitive> primitives;
};
struct GltfCamera
{
std::variant<fx::gltf::Camera::Perspective, fx::gltf::Camera::Orthographic> projection;
};
struct GltfNode
{
std::string name;
Transform transform;
std::optional<entt::resource<GltfMesh>> mesh;
std::optional<GltfCamera> camera;
std::vector<entt::resource<GltfNode>> children;
};
struct Gltf
{
std::vector<entt::resource<Material>> materials;
std::vector<entt::resource<GltfMesh>> meshes;
std::vector<entt::resource<GltfNode>> nodes;
std::vector<entt::resource<Scene>> scenes;
std::optional<entt::resource<Scene>> default_scene;
fx::gltf::Document document;
};

View File

@@ -1,5 +1,9 @@
#include "gltf_loader.h"
#include "camera.h"
#include "definitions/attribute_locations.h"
#include "name.h"
#include "relationship.h"
#include "scene.h"
#include "util/Log.h"
#include <iterator>
@@ -74,7 +78,8 @@ static auto load_material(fx::gltf::Material const &material,
std::filesystem::path const &document_path,
entt::resource_cache<Material> &material_cache,
entt::resource_cache<Image> &image_cache,
entt::resource_cache<Shader, ShaderLoader> &shader_cache) -> entt::resource<Material>
entt::resource_cache<Shader, ShaderLoader> &shader_cache)
-> entt::resource<Material>
{
auto base_color_texture_id = material.pbrMetallicRoughness.baseColorTexture.index;
auto normal_texture_id = material.normalTexture.index;
@@ -315,6 +320,23 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
return {};
}();
auto camera = [this, &node, &gltf]() -> std::optional<GltfCamera> {
if (node.camera != -1) {
auto const &camera = gltf.cameras.at(node.camera);
if (camera.type != fx::gltf::Camera::Type::Perspective) {
Log::logger().warn("Only perspective projections supported.");
}
// Only perspective supported until now
GltfCamera gltf_camera{.projection = camera.perspective};
return {gltf_camera};
}
return {};
}();
glm::vec3 translation(node.translation[0], node.translation[1], node.translation[2]);
glm::quat rotation(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]);
glm::vec3 scale(node.scale[0], node.scale[1], node.scale[2]);
@@ -326,12 +348,14 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
}
entt::hashed_string node_hash(node.name.c_str());
entt::resource<GltfNode> node_resource =
gltf_node_cache
.load(node_hash,
GltfNode{
.name = node.name, .transform = transform, .mesh = mesh, .children = {}})
.first->second;
entt::resource<GltfNode> node_resource = gltf_node_cache
.load(node_hash,
GltfNode{.name = node.name,
.transform = transform,
.mesh = mesh,
.camera = camera,
.children = {}})
.first->second;
nodes_map.emplace(i, node_resource);
}
@@ -356,35 +380,103 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
}
// Load scenes
std::vector<entt::resource<GltfScene>> scenes;
for (auto const &scene : gltf.scenes) {
std::vector<entt::resource<Scene>> scenes;
for (auto const &gltf_scene : gltf.scenes) {
// Get nodes by hash
std::vector<entt::resource<GltfNode>> nodes;
nodes.reserve(scene.nodes.size());
nodes.reserve(gltf_scene.nodes.size());
for (auto node_id : scene.nodes) {
for (auto node_id : gltf_scene.nodes) {
auto const &node = gltf.nodes.at(node_id);
entt::hashed_string node_hash(node.name.c_str());
nodes.push_back(gltf_node_cache[node_hash]);
}
if (scene.name.empty()) {
if (gltf_scene.name.empty()) {
Log::logger().warn("glTF scene has no name.");
}
entt::hashed_string scene_hash(scene.name.c_str());
entt::resource<GltfScene> scene_resource =
gltf_scene_cache.load(scene_hash, GltfScene{.nodes = std::move(nodes)}).first->second;
entt::registry registry;
// Spawn an entity for every node in scene
for (auto const &node : nodes) {
std::function<entt::entity(GltfNode const &, std::optional<entt::entity>)> spawn_node =
[this, &spawn_node, &registry](GltfNode const &node,
std::optional<entt::entity> parent) {
auto entity = registry.create();
registry.emplace<Name>(entity, node.name);
registry.emplace<Transform>(entity, node.transform);
registry.emplace<GlobalTransform>(entity, GlobalTransform{});
if (parent.has_value()) {
registry.emplace<Parent>(entity, Parent{.parent = parent.value()});
}
std::vector<entt::entity> child_entities;
auto mesh = node.mesh;
if (mesh.has_value()) {
for (auto const &primitive : mesh.value()->primitives) {
auto mesh_entity = registry.create();
registry.emplace<Parent>(mesh_entity, Parent{.parent = entity});
registry.emplace<Transform>(mesh_entity, Transform{});
registry.emplace<GlobalTransform>(mesh_entity, GlobalTransform{});
registry.emplace<entt::resource<Mesh>>(mesh_entity, primitive.mesh);
registry.emplace<entt::resource<Material>>(mesh_entity,
primitive.material);
child_entities.push_back(mesh_entity);
}
}
auto camera = node.camera;
if (camera.has_value()) {
auto perspective =
std::get<fx::gltf::Camera::Perspective>(camera.value().projection);
Camera::Perspective camera_perspective{.fov = perspective.yfov,
.aspect_ratio =
perspective.aspectRatio,
.near = perspective.znear,
.far = perspective.zfar};
registry.emplace<Camera>(entity, Camera{.projection = camera_perspective});
}
// Spawn child nodes
for (auto const &child : node.children) {
auto child_entity = spawn_node(child, entity);
child_entities.push_back(child_entity);
}
registry.emplace<Children>(entity, Children{.children = child_entities});
return entity;
};
spawn_node(node, {});
}
auto camera_view = registry.view<Camera const>();
if (camera_view.empty()) {
// Spawn default camera
auto entity = registry.create();
registry.emplace<Name>(entity, "Camera");
registry.emplace<Transform>(entity, Transform{.translation = Camera::DEFAULT_POSITION});
registry.emplace<GlobalTransform>(entity, GlobalTransform{});
registry.emplace<Camera>(entity, Camera{.projection = Camera::Perspective{}});
}
entt::hashed_string scene_hash(gltf_scene.name.c_str());
entt::resource<Scene> scene_resource =
scene_cache.load(scene_hash, Scene{std::move(registry)}).first->second;
scenes.push_back(scene_resource);
}
// Default scene
entt::resource<GltfScene> default_scene = [&gltf, &scenes]() {
auto default_scene = [&gltf, &scenes]() -> std::optional<entt::resource<Scene>> {
if (gltf.scene != -1) {
return scenes.at(gltf.scene);
}
return scenes.at(0);
return {};
}();
return std::make_shared<Gltf>(Gltf{.materials = std::move(materials),

View File

@@ -1,8 +1,6 @@
#pragma once
#include "image.h"
#include "material.h"
#include "mesh.h"
#include "gltf.h"
#include "transform.h"
#include <entt/entt.hpp>
@@ -11,41 +9,6 @@
static constexpr auto MAX_SIZE = 512 * 1024 * 1024;
struct GltfPrimitive
{
entt::resource<Mesh> mesh;
entt::resource<Material> material;
};
struct GltfMesh
{
std::vector<GltfPrimitive> primitives;
};
struct GltfNode
{
std::string name;
Transform transform;
std::optional<entt::resource<GltfMesh>> mesh;
std::vector<entt::resource<GltfNode>> children;
};
struct GltfScene {
std::vector<entt::resource<GltfNode>> nodes;
};
// Move to own file.
struct Gltf
{
std::vector<entt::resource<Material>> materials;
std::vector<entt::resource<GltfMesh>> meshes;
std::vector<entt::resource<GltfNode>> nodes;
std::vector<entt::resource<GltfScene>> scenes;
entt::resource<GltfScene> default_scene;
fx::gltf::Document document;
};
struct GltfLoader final
{
using result_type = std::shared_ptr<Gltf>;
@@ -56,8 +19,8 @@ struct GltfLoader final
entt::resource_cache<Material> &material_cache;
entt::resource_cache<Mesh> &mesh_cache;
entt::resource_cache<Shader, ShaderLoader> &shader_cache;
entt::resource_cache<Scene> &scene_cache;
entt::resource_cache<GltfMesh> &gltf_mesh_cache;
entt::resource_cache<GltfNode> &gltf_node_cache;
entt::resource_cache<GltfScene> &gltf_scene_cache;
};

75
src/scene.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "scene.h"
#include "camera.h"
#include "mesh.h"
#include "name.h"
#include "relationship.h"
#include "shader.h"
#include "transform.h"
#include "util/Log.h"
Scene::Scene(entt::registry registry) : m_registry(std::move(registry))
{
auto mesh_view = m_registry.view<entt::resource<Mesh>>();
for (auto [entity, mesh] : mesh_view.each()) {
m_registry.emplace<GpuMesh>(entity, GpuMesh(mesh));
// Remove Mesh resource as it is no longer needed.
m_registry.erase<entt::resource<Mesh>>(entity);
}
auto material_view = m_registry.view<entt::resource<Material>>();
for (auto [entity, material] : material_view.each()) {
m_registry.emplace<GpuMaterial>(entity, GpuMaterial(material));
// Remove Material resource as it is no longer needed.
m_registry.erase<entt::resource<Material>>(entity);
}
}
void Scene::update(std::chrono::duration<float> delta,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio,
bool cursor_catched)
{
{
// Update GlobalTransform components
// TODO: Only do this when the Transform changed.
auto root_transform_view =
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
for (auto [entity, transform, global_transform] : root_transform_view.each()) {
global_transform = transform;
auto parent_global_transform = global_transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
std::function<void(entt::entity entity,
GlobalTransform parent_global_transform)>
transform_propagate = [this, &transform_propagate, &transform_view](
entt::entity entity,
GlobalTransform parent_global_transform) {
auto [transform, global_transform, parent] = transform_view.get(entity);
global_transform.transform = parent_global_transform.transform *
GlobalTransform(transform).transform;
if (auto *children = m_registry.try_get<Children>(entity)) {
for (auto child : children->children) {
transform_propagate(child, global_transform);
}
}
};
transform_propagate(child, parent_global_transform);
}
}
}
}
Camera::aspect_ratio_update(m_registry, aspect_ratio);
Camera::keyboard_movement(m_registry, key_input, delta);
if (cursor_catched) {
Camera::mouse_orientation(m_registry, mouse_cursor_input);
}
}

26
src/scene.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include "input.h"
#include "gltf.h"
#include <chrono>
#include <entt/entt.hpp>
class Shader;
class Scene
{
public:
Scene(entt::registry registry);
void update(std::chrono::duration<float> delta_time,
KeyInput const &key_input,
MouseCursorInput const &mouse_cursor_input,
float aspect_ratio,
bool cursor_catched);
auto registry() -> entt::registry & { return m_registry; }
private:
entt::registry m_registry;
};

View File

@@ -33,11 +33,11 @@ Shader::Shader(std::string_view name, std::filesystem::path const &directory)
}
#ifdef NDEBUG
glDetachShader(m_ShaderId, vertexShader);
glDetachShader(m_ShaderId, fragmentShader);
glDetachShader(program, vertex_shader);
glDetachShader(program, fragment_shader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
#endif
Log::logger().trace(R"(Loaded Shader "{}")", name);