#include "Scene.h" #include "ShaderProgram.h" #include "camera.h" #include "mesh.h" #include "name.h" #include "relationship.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() { GltfLoader loader{.image_cache = m_image_cache, .material_cache = m_material_cache, .mesh_cache = m_mesh_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_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_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)> spawn_node = [this, &spawn_node](GltfNode const &node, std::optional parent) { auto entity = m_registry.create(); m_registry.emplace(entity, node.name); m_registry.emplace(entity, node.transform); m_registry.emplace(entity, GlobalTransform{}); if (parent.has_value()) { m_registry.emplace(entity, Parent{.parent = parent.value()}); } std::vector 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(mesh_entity, Parent{.parent = entity}); m_registry.emplace(mesh_entity, Transform{}); m_registry.emplace(mesh_entity, GlobalTransform{}); m_registry.emplace>(mesh_entity, primitive.mesh); m_registry.emplace>(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(entity, Children{.children = child_entities}); return entity; }; spawn_node(node, {}); } auto mesh_view = m_registry.view>(); for (auto [entity, mesh] : mesh_view.each()) { m_registry.emplace(entity, GpuMesh(mesh)); // Remove Mesh resource as it is no longer needed. m_registry.erase>(entity); } auto material_view = m_registry.view>(); for (auto [entity, material] : material_view.each()) { m_registry.emplace(entity, GpuMaterial(material)); // Remove Material resource as it is no longer needed. m_registry.erase>(entity); } // Spawn the camera auto entity = m_registry.create(); m_registry.emplace(entity, "Camera"); m_registry.emplace(entity, Transform{.translation = glm::vec3(0.0, 0.5, -1.0)}); m_registry.emplace(entity, GlobalTransform{}); m_registry.emplace(entity, Camera{.projection = Camera::Perspective{}}); } void Scene::update(std::chrono::duration delta, KeyInput const &key_input, MouseCursorInput const &mouse_cursor_input, float aspect_ratio) { { // Update GlobalTransform components // TODO: Only do this when the Transform changed. auto root_transform_view = m_registry.view(entt::exclude); auto transform_view = m_registry.view(); 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(entity)) { for (auto child : children->children) { std::function 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(entity)) { for (auto child : children->children) { transform_propagate(child, global_transform); } } }; transform_propagate(child, parent_global_transform); } } } } Camera::keyboard_movement(m_registry, key_input, delta); Camera::mouse_orientation(m_registry, mouse_cursor_input); Camera::aspect_ratio_update(m_registry, aspect_ratio); } void Scene::draw(ShaderProgram *shaderprogram) const { auto mesh_view = m_registry.view(); auto camera_view = m_registry.view(); auto camera_entity = camera_view.front(); auto [camera, camera_transform] = camera_view.get(camera_entity); glm::mat4 view_projection_matrix = camera.projection_matrix() * Camera::view_matrix(camera_transform); for (auto [entity, mesh, material, transform] : mesh_view.each()) { shaderprogram->bind(); // Bind textures material.bind(*shaderprogram); // Bind modelview matrix uniform { glm::mat4 modelViewProj = view_projection_matrix * transform.transform; shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj); shaderprogram->setUniform("u_modelMatrix", transform.transform); shaderprogram->setUniform("u_viewPosition", camera_transform.position()); } glBindVertexArray(mesh.vao); glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr); glBindVertexArray(0); ShaderProgram::unbind(); } }