329 lines
11 KiB
C++
329 lines
11 KiB
C++
// Copyright (c) 2022 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#pragma once
|
|
#include "scene/Scene.hpp"
|
|
#include "util/array.hpp"
|
|
|
|
namespace Dawn {
|
|
class SceneItemComponent;
|
|
|
|
class SceneItem :
|
|
public StateOwner,
|
|
public std::enable_shared_from_this<SceneItem>
|
|
{
|
|
private:
|
|
std::vector<std::shared_ptr<SceneItemComponent>> components;
|
|
// Local (real) values
|
|
glm::vec3 localPosition;
|
|
glm::vec3 localScale;
|
|
glm::quat localRotation;
|
|
|
|
// Cached (non-real) values
|
|
glm::mat4 transformLocal;
|
|
glm::mat4 transformWorld;
|
|
|
|
// glm::vec3 position;
|
|
// glm::vec3 scale;
|
|
// glm::quat rotation;
|
|
|
|
// Heirarchy
|
|
std::weak_ptr<SceneItem> parent;
|
|
std::vector<std::weak_ptr<SceneItem>> children;
|
|
|
|
// Hidden methods
|
|
void updateLocalValuesFromLocalTransform();
|
|
void updateLocalTransformFromLocalValues();
|
|
void updateWorldTransformFromLocalTransform();
|
|
void updateLocalTransformFromWorldTransform();
|
|
void updateChildrenTransforms();
|
|
|
|
public:
|
|
Scene *scene;
|
|
sceneitemid_t id;
|
|
// I have no idea if I'm keeping this
|
|
StateEvent<> eventTransformUpdated;
|
|
|
|
/**
|
|
* Constructor for a SceneItem. Scene Items should only be called and
|
|
* initialized by the scene itself.
|
|
*
|
|
* @param scene Weak pointer to the Scene that this SceneItem belongs to.
|
|
* @param id Scene Item ID that the Scene assigned this SceneItem.
|
|
*/
|
|
SceneItem(Scene *scene, sceneitemid_t id);
|
|
|
|
/**
|
|
* Called by the Scene the frame after we were constructed so we can begin
|
|
* existing.
|
|
*/
|
|
void init();
|
|
|
|
/**
|
|
* Called by the Scene when cleanup needs to occur but before anything in
|
|
* the scene has been disposed.
|
|
*/
|
|
void destroy();
|
|
|
|
/**
|
|
* Adds a component to this scene item. Components will only have their
|
|
* init methods invoked on the first frame we enter the scene. If you add
|
|
* a component to this item after this time you will either need to try
|
|
* manually invoking its' init method, or ensure the component is aware of
|
|
* the entire SceneItem lifecycle and listen for added callbacks.
|
|
*
|
|
* @tparam T Type of component being added to this scene item.
|
|
* @return A shared pointer to the newly added component.
|
|
*/
|
|
template<class T>
|
|
std::shared_ptr<T> addComponent() {
|
|
auto component = std::make_shared<T>(this);
|
|
this->components.push_back(component);
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* Returns a component attached to this SceneItem. This method will return
|
|
* either a shared pointer to the component, or nullptr if the item does
|
|
* not have the queried component.
|
|
*
|
|
* @tparam T Type of component to be fetched.
|
|
* @return A shared pointer to the component, or nullptr if not found.
|
|
*/
|
|
template<class T>
|
|
std::shared_ptr<T> getComponent() {
|
|
auto it = this->components.begin();
|
|
while(it != this->components.end()) {
|
|
std::shared_ptr<T> castedAs = std::dynamic_pointer_cast<T>(*it);
|
|
if(castedAs != nullptr) return castedAs;
|
|
++it;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/**
|
|
* Returns all components attached to this SceneItem that match the
|
|
* queried component type. This method will return an array of shared
|
|
* pointers to the components, or an empty array if the item does not have
|
|
* any components of the queried type.
|
|
*
|
|
* @tparam T Type of component to be fetched.
|
|
* @return An array of pointers to the components.
|
|
*/
|
|
template<class T>
|
|
std::vector<std::shared_ptr<T>> getComponents() {
|
|
std::vector<std::shared_ptr<T>> components;
|
|
auto it = this->components.begin();
|
|
while(it != this->components.end()) {
|
|
T *castedAs = std::dynamic_pointer_cast<T>(it);
|
|
if(castedAs != nullptr) components.push_back(castedAs);
|
|
++it;
|
|
}
|
|
return components;
|
|
}
|
|
|
|
/**
|
|
* Finds a (direct) child of this component that has a matching component.
|
|
*
|
|
* @tparam T Component to find child of.
|
|
* @return Pointer to the child, or nullptr if not found.
|
|
*/
|
|
template<class T>
|
|
std::shared_ptr<T> findChild() {
|
|
auto it = this->children.begin();
|
|
while(it != this->children.end()) {
|
|
auto childItem = it->lock();
|
|
if(childItem == nullptr) {
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
auto childComponent = childItem->getComponent<T>();
|
|
if(childComponent != nullptr) return childComponent;
|
|
++it;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/**
|
|
* Finds all (direct) children of this component that match the queried
|
|
* component.
|
|
*
|
|
* @tparam T Component to find children for.
|
|
* @return Array of pointers to matching children.
|
|
*/
|
|
template<class T>
|
|
std::vector<std::shared_ptr<T>> findChildren() {
|
|
auto it = this->children.begin();
|
|
std::vector<std::shared_ptr<T>> children;
|
|
while(it != this->children.end()) {
|
|
auto childItem = it->lock();
|
|
if(childItem == nullptr) {
|
|
++it;
|
|
continue;
|
|
}
|
|
auto childComponent = childItem->getComponent<T>();
|
|
if(childComponent != nullptr) children.push_back(childComponent);
|
|
++it;
|
|
}
|
|
return children;
|
|
}
|
|
|
|
/**
|
|
* Finds all children, and children of children, recursively that match
|
|
* the queried component.
|
|
*
|
|
* @tparam T Component Type to find.
|
|
* @return Array of pointers to matching children components.
|
|
*/
|
|
template<class T>
|
|
std::vector<std::shared_ptr<T>> findChildrenDeep() {
|
|
auto childrenToCheck = this->children;
|
|
std::vector<std::shared_ptr<T>> itemsFound;
|
|
|
|
while(childrenToCheck.size() > 0) {
|
|
auto it = *childrenToCheck.begin();
|
|
auto otherItem = it.lock();
|
|
if(otherItem != nullptr) {
|
|
vectorAppend(childrenToCheck, otherItem->children);
|
|
}
|
|
auto component = otherItem->getComponent<T>();
|
|
if(component != nullptr) itemsFound.push_back(component);
|
|
childrenToCheck.erase(childrenToCheck.begin());
|
|
}
|
|
|
|
return itemsFound;
|
|
}
|
|
|
|
// // // // // // // // // // // // // // // // // // // // // // // // //
|
|
|
|
/**
|
|
* Orients this transform to look at a given point in world space.
|
|
*
|
|
* @param position Position of the origin of this transform.
|
|
* @param look Position in world space this transform looks at.
|
|
*/
|
|
void lookAt(const glm::vec3 position, const glm::vec3 look);
|
|
void lookAt(
|
|
const glm::vec3 position,
|
|
const glm::vec3 look,
|
|
const glm::vec3 up
|
|
);
|
|
|
|
/**
|
|
* Shorthand combined for lookAt and perspectivePixelPerfectDistance
|
|
* to allow you to create pixel perfect lookAt camera view matricies.
|
|
*
|
|
* @param position Position of the camera. Z is for an offset.
|
|
* @param look Position in world space this transform looks at.
|
|
* @param viewportHeight Height of the viewport.
|
|
* @param fov Field of view (in radians).
|
|
* @return The Z distance that was calculated.
|
|
*/
|
|
float_t lookAtPixelPerfect(
|
|
const glm::vec3 position,
|
|
const glm::vec3 look,
|
|
const float_t viewportHeight,
|
|
const float_t fov
|
|
);
|
|
|
|
/**
|
|
* Returns the local position (position relative to "my parent").
|
|
* @return The 3D local position in parent-relative space.
|
|
*/
|
|
glm::vec3 getLocalPosition();
|
|
|
|
/**
|
|
* Update / Set the local position of this transform relative to my parent
|
|
* @param position Position to set for the local transform.
|
|
*/
|
|
void setLocalPosition(const glm::vec3 position);
|
|
|
|
/**
|
|
* Retusn the scale of this item, relative to my parent.
|
|
* @return 3D Scale vector of this item in parent-relative space.
|
|
*/
|
|
glm::vec3 getLocalScale();
|
|
|
|
/**
|
|
* Set the local scale of this item.
|
|
* @param scale Scale of this item, relative to its parent.
|
|
*/
|
|
void setLocalScale(const glm::vec3 scale);
|
|
|
|
/**
|
|
* Returns the local rotation for this transform.
|
|
* @return The local rotation (parent-relative).
|
|
*/
|
|
glm::quat getLocalRotation();
|
|
|
|
/**
|
|
* Set the local (parent-relative) rotation for this transform.
|
|
* @param rotation Rotation in parent relative space.
|
|
*/
|
|
void setLocalRotation(const glm::quat rotation);
|
|
|
|
/**
|
|
* Returns the transform matrix for this transform, in parent-relative
|
|
* space.
|
|
* @return The transform origin in parent-relative space.
|
|
*/
|
|
glm::mat4 getLocalTransform();
|
|
|
|
/**
|
|
* Sets the local transform matrix for this transform.
|
|
* @param transform Local (parent-relative) transform to set.
|
|
*/
|
|
void setLocalTransform(const glm::mat4 transform);
|
|
|
|
/**
|
|
* Returns the position of the origin of this transform in world-space.
|
|
*
|
|
* @return Transform origin in world-space.
|
|
*/
|
|
glm::vec3 getWorldPosition();
|
|
|
|
/**
|
|
* Returns the transformation matrix for this transform, in world-space.
|
|
* @return The transform origin in world-space.
|
|
*/
|
|
glm::mat4 getWorldTransform();
|
|
|
|
/**
|
|
* Updates the transform's world-space.
|
|
* @param transform Sets the transform position in world-space.
|
|
*/
|
|
void setWorldTransform(const glm::mat4 transform);
|
|
|
|
/**
|
|
* Updates the transform that this transform is a child of. Will also
|
|
* handle disconnecting any existing parent.
|
|
*
|
|
* @param p Parent that this transform is now a child of.
|
|
*/
|
|
void setParent(const std::shared_ptr<SceneItem> p);
|
|
|
|
/**
|
|
* Returns the parent transform of this transform, or nullptr if there is
|
|
* no parent for this transform.
|
|
* @return Pointer to the parent transform, or nullptr.
|
|
*/
|
|
std::weak_ptr<SceneItem> getParent();
|
|
|
|
/**
|
|
* Returns true if this transform is a child of the given transform, this
|
|
* climbs up the heirarchy until it finds a match.
|
|
*
|
|
* @param p Transform to check if this transform is a child of.
|
|
* @return True if this transform is a child of the given transform.
|
|
*/
|
|
bool_t isChildOf(std::shared_ptr<SceneItem> p);
|
|
|
|
/**
|
|
* Destroy this SceneItem.
|
|
*/
|
|
~SceneItem();
|
|
};
|
|
} |