From cb545da50f09ecd67f2c86ad2463325d57b2c94a Mon Sep 17 00:00:00 2001 From: Curle Date: Sun, 12 Mar 2023 14:19:58 +0000 Subject: [PATCH] Entity Spatial Component API draft. --- .../shadow-engine/core/inc/math/bounds.h | 23 ++++ .../shadow-engine/core/inc/math/transform.h | 47 +++++++ .../inc/component/EntitySpatialComponent.h | 130 ++++++++++++++++++ 3 files changed, 200 insertions(+) create mode 100644 projs/shadow/shadow-engine/core/inc/math/bounds.h create mode 100644 projs/shadow/shadow-engine/core/inc/math/transform.h create mode 100644 projs/shadow/shadow-engine/shadow-entity/inc/component/EntitySpatialComponent.h diff --git a/projs/shadow/shadow-engine/core/inc/math/bounds.h b/projs/shadow/shadow-engine/core/inc/math/bounds.h new file mode 100644 index 0000000..8afed68 --- /dev/null +++ b/projs/shadow/shadow-engine/core/inc/math/bounds.h @@ -0,0 +1,23 @@ +#pragma once +#include + +/** + * A temporary header that contains some of the bounds implementations. + */ + +namespace Math { + + /** + * A bounding box that can be rotated freely. + * Can be used as the collision box for an entity. + */ + struct OrientedBB { + + OrientedBB() = default; + + + Quaternion orientation; + Vector center; + Vector extent; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/core/inc/math/transform.h b/projs/shadow/shadow-engine/core/inc/math/transform.h new file mode 100644 index 0000000..d489dbf --- /dev/null +++ b/projs/shadow/shadow-engine/core/inc/math/transform.h @@ -0,0 +1,47 @@ +#pragma once + +/** + * A temporary header that contains some of the core transform logic. + * + */ + +#include + +namespace Math { + + struct alignas(16) Vector { + Vector() = default; + + union { + struct { float x, y, z, w; }; + __m128 data; + }; + }; + + struct alignas(16) Quaternion { + + inline Quaternion() = default; + + union { + struct { float x, y, z, w; }; + __m128 data; + }; + }; + + class Transform { + public: + Transform() = default; + + const Vector& GetTranslation() const { return translation; } + const Quaternion& GetRotation() const { return rotation; } + + inline Vector GetRightVector() const; + inline Vector GetForwardVector() const; + inline Vector GetUpVector() const; + + private: + Quaternion rotation; + Vector translation; + Vector scale; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-entity/inc/component/EntitySpatialComponent.h b/projs/shadow/shadow-engine/shadow-entity/inc/component/EntitySpatialComponent.h new file mode 100644 index 0000000..efae695 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-entity/inc/component/EntitySpatialComponent.h @@ -0,0 +1,130 @@ +#pragma once +#include + +namespace SE { + + /** + * An Entity Component that has a Spatial context. + * AKA, a Component with a position, a rotation, and a size. + * + * Spatial Components may exist in a hierarchy; where each subsequent object inherits the spatial positions of its' parents. + * This allows for things like complex articulation of large machines, etc. + */ + class EntitySpatialComponent : public EntityComponent { + public: + + // Whether this is the root spatial component for this Entity. + inline bool IsSpatialRoot() const { return parent == nullptr; } + + // Fetch the transforms and bounds. + inline Math::Transform const& GetLocalTransform() const { return transform; } + inline Math::OrientedBB const& GetLocalBounds() const { return bounds; } + + inline Math::Transform const& GetWorldTransform() const { return worldTransform; } + inline Math::OrientedBB const& GetWorldBounds() const { return worldBounds; } + + // Get the position in world-space. + inline Math::Vector const& GetPosition() const { return worldTransform.GetTranslation(); } + + // Get the rotation in world-space. + inline Math::Quaternion const& GetRotation() const { return worldTransform.GetRotation(); } + + // Get vectors relative to this spatial component. + inline Math::Vector GetForwardVector() const { return worldTransform.GetForwardVector(); } + inline Math::Vector GetUpVector() const { return worldTransform.GetUpVector(); } + inline Math::Vector GetRightVector() const { return worldTransform.GetRightVector(); } + + // Update the local and world transforms + inline void SetLocalTransform(Math::Transform const& newTransform); + inline void SetWorldTransform(Math::Transform const& newTransform); + + // Move this component by the specified amount of transform, rotation + inline void MoveBy(Math::Transform const& delta); + + + // Is there a child spatial component + inline bool HasChildren() const { return !children.empty(); } + + // Get the ID of the parent of this Spatial Component + inline ComponentID const& GetParentID() const { return parent->GetID(); } + + // Get the transform of the parent component + inline Math::Transform const& GetParentTransform() const { return parent->worldTransform; } + + // Fetch how deep in the spatial hierarchy this Component is. + size_t GetHierarchyDepth(bool singleEntity = true) const; + + // Check if we are a child of a given Component + bool IsChildOf(EntitySpatialComponent const* parent) const; + + // Get the ID of the socket we are attached to + inline std::string const& GetAttachmentSocketID() const { return attachmentSocket; } + + // Set the name of the socket we wish to be attached to. + inline void SetAttachmentSocket(std::string& id) { attachmentSocket = id;} + + // Fetch the transform of a specific attachment. + Math::Transform const& GetAttachmentTransform(std::string& id) const; + + // Whether this Component supports local scaling + virtual bool LocalScale() const { return false; } + // Fetch the local scale, if supported. { 1, 1, 1 } otherwise. + virtual std::array const& GetLocalScale() const { static auto ones = std::array { 1, 1, 1 }; return ones; } + + // Convert a given world-space transform to a model-space transform. + inline Math::Transform const& ConvertWorldToLocalTransform(Math::Transform const& world); + + + protected: + + virtual void Initialize() override; + + // Set the local scale, if supported + virtual void SetLocalScale(std::array const& newScale) {} + + // Calculate the local bounding box for the Component; the position should always be close to origin. + virtual Math::OrientedBB CalculateBounds() const; + + // Update the local and world bounds for the Component. + void UpdateBounds(); + + // Attempt to find the given Socket in this Component, and return its' Transform if present. + bool GetAttachmentTransform(std::string& socketId, Math::Transform& out) const; + virtual bool FindAttachmentTransform(std::string& socketId, Math::Transform& out) const; + + // Whether this Component has the given Socket. + // Default: No sockets. + virtual bool HasSocket(std::string& socket) const { return false;} + + // Process the creation/destruction/movement of a Socket. + void UpdateSockets(); + + // Called whenever the World Transform is updated. + virtual void OnMoved() {} + + // Set the World Transform for a component. + // Skips a lot of internal processing. + inline void SetWorldTransform(Math::Transform& newTransform, bool callback = true); + + private: + + inline void CalculateWorldTransform(bool callback = true); + + // The location of this Component, relative to the world. + Math::Transform transform; + // The collision boundary of this Component. + Math::OrientedBB bounds; + + // The world transform of this component; how to get to the position from the world origin. + Math::Transform worldTransform; + Math::OrientedBB worldBounds; + + // The parent of this Spatial Component + EntitySpatialComponent* parent = nullptr; + // The socket (attachment point) of the parent entity that this Component is attached to. + std::string attachmentSocket; + // The Components that are attached to this Component. + std::vector children; + + }; +} \ No newline at end of file