Component+Scene+System: Implement parent-child transform components

This commit is contained in:
Riyyi
2024-01-05 20:50:49 +01:00
parent 0dd7a05d46
commit bc3f2c9db5
8 changed files with 153 additions and 60 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022-2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
@@ -18,7 +18,7 @@ namespace Inferno {
struct TextAreaComponent {
std::string content;
std::string font;
unsigned char fontSize { 0 };
unsigned char fontSize { 12 };
float lineSpacing { 1.0f };
uint32_t width { 0 };
+8 -1
View File
@@ -1,11 +1,16 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022,2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstdint> // uint32_t
#include <optional>
#include "entt/entity/entity.hpp" // entt::null
#include "entt/entity/fwd.hpp" // entt::entity
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/format/format.h"
@@ -17,6 +22,8 @@ struct TransformComponent {
glm::vec3 translate { 0.0f, 0.0f, 0.0f };
glm::vec3 rotate { 0.0f, 0.0f, 0.0f };
glm::vec3 scale { 1.0f, 1.0f, 1.0f };
entt::entity parent { entt::null };
glm::mat4 transform { 1.0f }; // Identity matrix
};
+69 -49
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022-2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
@@ -8,6 +8,7 @@
#include <cstdint> // uint32_t
#include <limits> // std::numeric_limits
#include "entt/entity/entity.hpp" // ent::entity
#include "ruc/file.h"
#include "ruc/format/log.h"
#include "ruc/json/json.h"
@@ -62,54 +63,7 @@ void Scene::initialize()
VERIFY(entityJson.type() == ruc::Json::Type::Array);
const auto& entities = entityJson.asArray();
for (size_t i = 0; i < entities.size(); ++i) {
uint32_t entity = createEntity();
VERIFY(entities.at(i).type() == ruc::Json::Type::Object);
const auto& components = entities.at(i);
// ID is required
VERIFY(components.exists("id"), "id not found");
auto& id = getComponent<IDComponent>(entity);
components.at("id").getTo(id);
if (components.exists("tag")) {
auto& tag = getComponent<TagComponent>(entity);
components.at("tag").getTo(tag);
}
if (components.exists("transform")) {
auto& transform = getComponent<TransformComponent>(entity);
components.at("transform").getTo(transform);
}
if (components.exists("camera")) {
auto& camera = addComponent<CameraComponent>(entity);
components.at("camera").getTo(camera);
}
if (components.exists("lua-scripts")) {
VERIFY(components.at("lua-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("lua-scripts").asArray();
for (size_t j = 0; j < scripts.size(); ++j) {
auto& script = addComponent<LuaScriptComponent>(entity);
scripts.at(j).getTo(script);
}
}
if (components.exists("native-scripts")) {
VERIFY(components.at("native-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("native-scripts").asArray();
for (size_t j = 0; j < scripts.size(); ++j) {
auto& script = addComponent<NativeScriptComponent>(entity);
scripts.at(j).getTo(script);
script.bind();
}
}
if (components.exists("sprite")) {
auto& sprite = addComponent<SpriteComponent>(entity);
components.at("sprite").getTo(sprite);
}
if (components.exists("text")) {
auto& text = addComponent<TextAreaComponent>(entity);
components.at("text").getTo(text);
}
loadEntity(entities.at(i));
}
}
@@ -138,6 +92,8 @@ void Scene::destroy()
TransformSystem::destroy();
}
// -----------------------------------------
uint32_t Scene::createEntity(const std::string& name)
{
return createEntityWithUID(UID(), name);
@@ -150,6 +106,68 @@ uint32_t Scene::createEntityWithUID(UID id, const std::string& name)
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity);
TransformSystem::the().add(entity);
return entity;
}
uint32_t Scene::loadEntity(ruc::Json components, uint32_t parentEntity)
{
VERIFY(components.type() == ruc::Json::Type::Object);
uint32_t entity = createEntity();
// At minimum, ID is required
VERIFY(components.exists("id"), "id not found");
auto& id = getComponent<IDComponent>(entity);
components.at("id").getTo(id);
if (components.exists("tag")) {
auto& tag = getComponent<TagComponent>(entity);
components.at("tag").getTo(tag);
}
if (components.exists("transform")) {
auto& transform = getComponent<TransformComponent>(entity);
components.at("transform").getTo(transform);
transform.parent = static_cast<entt::entity>(parentEntity);
}
if (components.exists("camera")) {
auto& camera = addComponent<CameraComponent>(entity);
components.at("camera").getTo(camera);
}
if (components.exists("lua-scripts")) {
VERIFY(components.at("lua-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("lua-scripts").asArray();
for (size_t i = 0; i < scripts.size(); ++i) {
auto& script = addComponent<LuaScriptComponent>(entity);
scripts.at(i).getTo(script);
}
}
if (components.exists("native-scripts")) {
VERIFY(components.at("native-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("native-scripts").asArray();
for (size_t i = 0; i < scripts.size(); ++i) {
auto& script = addComponent<NativeScriptComponent>(entity);
scripts.at(i).getTo(script);
script.bind();
}
}
if (components.exists("sprite")) {
auto& sprite = addComponent<SpriteComponent>(entity);
components.at("sprite").getTo(sprite);
}
if (components.exists("text")) {
auto& text = addComponent<TextAreaComponent>(entity);
components.at("text").getTo(text);
}
if (components.exists("children")) {
VERIFY(components.at("children").type() == ruc::Json::Type::Array);
const auto& children = components.at("children").asArray();
for (size_t i = 0; i < children.size(); ++i) {
loadEntity(components.at("children")[i], entity);
}
}
return entity;
}
@@ -172,6 +190,8 @@ void Scene::destroyEntity(uint32_t entity)
m_registry->destroy(entt::entity { entity });
}
// -----------------------------------------
glm::mat4 Scene::cameraProjectionView()
{
return CameraSystem::the().projectionView();
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022,2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
@@ -31,6 +31,7 @@ public:
uint32_t createEntity(const std::string& name = "");
uint32_t createEntityWithUID(UID id, const std::string& name = "");
uint32_t loadEntity(ruc::Json components, uint32_t parentEntity = entt::null);
uint32_t findEntity(std::string_view name);
void destroyEntity(uint32_t entity);
+28 -2
View File
@@ -1,9 +1,13 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022,2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <algorithm> // std::sort
#include <cstdint> // uint32_t
#include "entt/entity/fwd.hpp" // entt:entity
#include "glm/ext/matrix_transform.hpp" // glm::translate, glm::rotate, glm::scale, glm::radians
#include "ruc/format/log.h"
@@ -25,7 +29,7 @@ void TransformSystem::update()
{
auto view = m_registry->view<TransformComponent>();
for (auto entity : view) {
for (auto entity : m_hierarchy) {
auto& component = view.get<TransformComponent>(entity);
@@ -42,7 +46,29 @@ void TransformSystem::update()
// Scale
component.transform = glm::scale(component.transform, component.scale);
// Apply the parent transform to the child transform
if (component.parent != entt::null) {
auto& parent = view.get<TransformComponent>(component.parent);
component.transform = parent.transform * component.transform;
}
}
}
void TransformSystem::add(uint32_t entity)
{
m_hierarchy.push_back(static_cast<entt::entity>(entity));
}
void TransformSystem::sort()
{
std::sort(m_hierarchy.begin(), m_hierarchy.end(),
[](entt::entity a, entt::entity b) {
return (a == entt::null && b == entt::null) ? false
: (a == entt::null) ? true
: (b == entt::null) ? false
: a < b;
});
}
} // namespace Inferno
+9 -2
View File
@@ -1,12 +1,14 @@
/*
* Copyright (C) 2022 Riyyi
* Copyright (C) 2022,2024 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <memory> // std::shared_ptr
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
#include <vector>
#include "entt/entity/registry.hpp" // entt::entity, entt::registry
#include "ruc/singleton.h"
@@ -20,9 +22,14 @@ public:
void update();
void add(uint32_t entity);
void sort();
void setRegistry(std::shared_ptr<entt::registry> registry) { m_registry = registry; };
private:
std::vector<entt::entity> m_hierarchy;
std::shared_ptr<entt::registry> m_registry;
};