From: Mikko Rasa Date: Sat, 22 Oct 2022 19:52:04 +0000 (+0300) Subject: Add a transform component and propagation system X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=c809f54b802727926bae40e9fe67d0e3c94fd2c0;p=libs%2Fgame.git Add a transform component and propagation system --- diff --git a/source/game/entity.cpp b/source/game/entity.cpp index 055c8d6..8f56f67 100644 --- a/source/game/entity.cpp +++ b/source/game/entity.cpp @@ -1,15 +1,27 @@ #include "entity.h" #include "component.h" #include "root.h" +#include "transform.h" using namespace std; namespace Msp::Game { -Entity::Entity(Handle p): +Entity::Entity(Handle p, TransformTag): parent(p) { } +Entity::Entity(Handle p, const TransformValues &tv): + parent(p), + transform(*this) +{ + transform->set_values(tv); +} + +// Hide ~Owned from the header +Entity::~Entity() +{ } + void Entity::add_component(Handle comp) { if(comp->get_entity().get()!=this) diff --git a/source/game/entity.h b/source/game/entity.h index 7c7ee89..c28cbe5 100644 --- a/source/game/entity.h +++ b/source/game/entity.h @@ -2,11 +2,14 @@ #define MSP_GAME_ENTITY_H_ #include "handle.h" +#include "owned.h" namespace Msp::Game { class Component; class Stage; +class Transform; +struct TransformValues; class hierarchy_error: public std::logic_error { @@ -16,13 +19,18 @@ public: class Entity { +public: + enum TransformTag { NO_TRANSFORM }; + private: Handle parent; std::vector> components; std::vector> children; + Owned transform; public: - Entity(Handle); + Entity(Handle, TransformTag); + Entity(Handle, const TransformValues &); virtual ~Entity(); void add_component(Handle); @@ -33,7 +41,9 @@ public: Handle get_parent() const { return parent; } Handle get_root(); + const std::vector> &get_children() const { return children; } Stage &get_stage(); + Handle get_transform() const { return transform; } }; diff --git a/source/game/root.h b/source/game/root.h index 4f7ea76..726ca32 100644 --- a/source/game/root.h +++ b/source/game/root.h @@ -13,7 +13,7 @@ private: Stage &stage; public: - Root(Stage &s): Entity(nullptr), stage(s) { } + Root(Stage &s): Entity(nullptr, NO_TRANSFORM), stage(s) { } Stage &get_stage() const { return stage; } }; diff --git a/source/game/transform.cpp b/source/game/transform.cpp new file mode 100644 index 0000000..6af24c0 --- /dev/null +++ b/source/game/transform.cpp @@ -0,0 +1,27 @@ +#include "transform.h" +#include + +namespace Msp::Game { + +Transform::Transform(Handle e): + Component(e) +{ } + +void Transform::set_values(const TransformValues &v) +{ + values = v; +} + +void Transform::update_world_matrix(const Transform *parent) +{ + using Affine = Geometry::AffineTransform; + + local_matrix = Affine::translation(values.position)* + Affine::rotation(values.rotation)*Affine::scaling(values.scale); + if(parent) + world_matrix = parent->get_world_matrix()*local_matrix; + else + world_matrix = local_matrix; +} + +} // namespace Msp::Game diff --git a/source/game/transform.h b/source/game/transform.h new file mode 100644 index 0000000..d698499 --- /dev/null +++ b/source/game/transform.h @@ -0,0 +1,40 @@ +#ifndef MSP_GAME_TRANSFORM_H_ +#define MSP_GAME_TRANSFORM_H_ + +#include +#include +#include +#include "component.h" + +namespace Msp::Game { + +struct TransformValues +{ + LinAl::Vector position; + Geometry::Quaternion rotation = Geometry::Quaternion::one(); + LinAl::Vector scale = { 1.0f, 1.0f, 1.0f }; +}; + +class Transform: public Component +{ +private: + TransformValues values; + LinAl::Matrix local_matrix; + LinAl::Matrix world_matrix; + +public: + Transform(Handle); + + void set_values(const TransformValues &); + const TransformValues &get_values() const { return values; } + const LinAl::Vector &get_position() const { return values.position; } + const Geometry::Quaternion &get_rotation() const { return values.rotation; } + const LinAl::Vector &get_scale() const { return values.scale; } + const LinAl::Matrix &get_world_matrix() const { return world_matrix; } + + void update_world_matrix(const Transform *); +}; + +} // namespace Msp::Game + +#endif diff --git a/source/game/transformpropagator.cpp b/source/game/transformpropagator.cpp new file mode 100644 index 0000000..73ecf64 --- /dev/null +++ b/source/game/transformpropagator.cpp @@ -0,0 +1,47 @@ +#include "transformpropagator.h" +#include "events.h" +#include "root.h" +#include "stage.h" +#include "transform.h" + +using namespace std; + +namespace Msp::Game { + +TransformPropagator::TransformPropagator(Stage &s): + System(s), + observer(s.get_event_bus()) +{ + observer.observe([this](const Events::EntityCreated &){ transforms_dirty = true; }); + observer.observe([this](const Events::EntityDestroyed &){ transforms_dirty = true; }); +} + +void TransformPropagator::tick(Time::TimeDelta) +{ + if(transforms_dirty) + rebuild_transform_order(); + + for(const ParentedTransform &t: transforms) + t.transform->update_world_matrix(t.parent.get()); +} + +void TransformPropagator::rebuild_transform_order() +{ + transforms.clear(); + for(Handle c: stage.get_root()->get_children()) + rebuild_transform_order(c, nullptr); +} + +void TransformPropagator::rebuild_transform_order(Handle entity, Handle parent_trans) +{ + if(Handle trans = entity->get_transform()) + { + transforms.emplace_back(trans, parent_trans); + parent_trans = trans; + } + + for(Handle c: entity->get_children()) + rebuild_transform_order(c, parent_trans); +} + +} // namespace Msp::Game diff --git a/source/game/transformpropagator.h b/source/game/transformpropagator.h new file mode 100644 index 0000000..3ac291b --- /dev/null +++ b/source/game/transformpropagator.h @@ -0,0 +1,38 @@ +#ifndef MSP_GAME_TRANSFORMPROPAGATOR_H_ +#define MSP_GAME_TRANSFORMPROPAGATOR_H_ + +#include "eventobserver.h" +#include "handle.h" +#include "system.h" + +namespace Msp::Game { + +class Entity; +class Transform; + +class TransformPropagator: public System +{ +private: + struct ParentedTransform + { + Handle transform; + Handle parent; + }; + + EventObserver observer; + std::vector transforms; + bool transforms_dirty = true; + +public: + TransformPropagator(Stage &); + + void tick(Time::TimeDelta) override; + +private: + void rebuild_transform_order(); + void rebuild_transform_order(Handle, Handle); +}; + +} // namespace Msp::Game + +#endif