#include "Transformable.hpp" #include "IdGenerator.hpp" #include "MathF.hpp" #include "BehaviourScript.hpp" #include "Layer.hpp" #include "Debug.hpp" namespace TSE { Transformable::Transformable() : position(0, 0, 0), scale(1, 1, 1), rotation(), name("") { id = GenerateRandomUUID(); objectEntries[id] = this; } Transformable::Transformable(uuids::uuid id) : id(id), position(0, 0, 0), scale(1, 1, 1), rotation(), name("") { objectEntries[id] = this; } Transformable::Transformable(const string &name) : position(0, 0, 0), scale(1, 1, 1), rotation(), name(name) { id = GenerateRandomUUID(); objectEntries[id] = this; } Transformable::Transformable(const string &name, uuids::uuid id) : id(id), position(0, 0, 0), scale(1, 1, 1), rotation(), name(name) { objectEntries[id] = this; } Vector3 Transformable::forward() const { return Vector3::Normalize(GetGlobalMatrix() * Vector3::forward - GetGlobalMatrix() * Vector3::zero); } Vector3 Transformable::right() const { return Vector3::Normalize(GetGlobalMatrix() * Vector3::right - GetGlobalMatrix() * Vector3::zero); } Vector3 Transformable::up() const { return Vector3::Normalize(GetGlobalMatrix() * Vector3::up - GetGlobalMatrix() * Vector3::zero); } Vector3 Transformable::GetPosition() const { return position; } void Transformable::SetPosition(const Vector3 &pos) { position = pos; } Quaternion Transformable::GetRotation() const { return rotation; } void Transformable::SetRotation(const Quaternion &rot) { rotation = rot; } Vector3 Transformable::GetScale() const { return scale; } void Transformable::SetScale(const Vector3 &s) { scale = s; } string Transformable::GetName() const { return name; } uuids::uuid Transformable::GetId() const { return id; } Vector3 Transformable::GetEuler() { return rotation.ToEulerAngles(); } void Transformable::SetEuler(const Vector3 &euler) { rotation = Quaternion::FromEulerAngles(euler); } int Transformable::GetComponentCount() { return components.size(); } Matrix4x4 Transformable::GetLocalMatrix() const { return Matrix4x4::ToTranslationMatrix(position) * Matrix4x4::ToRotationMatrix(rotation) * Matrix4x4::ToScaleMatrix(scale);; } Matrix4x4 Transformable::GetGlobalMatrix() const { if (parent != nullptr) return parent->GetGlobalMatrix() * GetLocalMatrix(); return GetLocalMatrix(); } Vector3 Transformable::GetGlobalPosition() const { return LocalToGlobalPosition(Vector3::zero); } Vector3 Transformable::GlobalToLocalPosition(const Vector3& global) const { Matrix4x4 globalMatrix = GetGlobalMatrix(); if(globalMatrix.IsAffine()) { globalMatrix.InvertAffine(); } else { globalMatrix.Invert(); } return globalMatrix * global; } Vector3 Transformable::LocalToGlobalPosition(const Vector3& local) const { return GetGlobalMatrix() * local; } void Transformable::LookAt_2D(const Vector3& globalTarget) { Vector3 to = globalTarget - GetGlobalPosition(); Vector3 toXY = {to.x, to.y, 0.0f}; if(Vector3::Dot(toXY, toXY) < TSE_EPSILON) return; toXY.Normalize(); Vector3 fwdWorld = rotation.Rotate(Vector3::up); Vector3 fwdXY = Vector3(fwdWorld.x, fwdWorld.y, 0); fwdXY.Normalize(); float cosA = std::clamp(Vector3::Dot(fwdXY, toXY), -1.0f, 1.0f); float sinA = fwdXY.x * toXY.y - fwdXY.y * toXY.x; float angle = atan2(sinA, cosA); Quaternion twist = Quaternion::FromAngleAxis(angle, Vector3::forward); rotation = twist * rotation; } void Transformable::SetParent(Transformable *p) { Transformable* t(this); if (parent != nullptr && parent != p) { auto it = parent->children.begin(); for (int i = 0; i < parent->children.size(); i++) { if(**it == *t) { parent->children.erase(it); break; } it++; } } if (p != nullptr && p != parent) { p->children.push_back(t); } parent = p; } Transformable *Transformable::GetParent() const { return parent; } const std::vector &Transformable::GetChildren() const { return children; } bool Transformable::IsMyChild(Transformable *other) { for (auto child : children) { if(child->id == other->id) { return true; } else if(child->IsMyChild(other)) { return true; } } return false; } void Transformable::MoveUp(Layer *l) { if(l != nullptr) { auto it = l->GetAllObjects().begin(); for(int i = 0; i < l->GetAllObjects().size(); i++) { if((*it)->id == id) { if(i == 0) return; std::swap(l->GetAllObjects()[i - 1], l->GetAllObjects()[i]); } it++; } return; } auto it = parent->children.begin(); for(int i = 0; i < parent->children.size(); i++) { if((*it)->id == id) { if(i == 0) return; std::swap(parent->children[i - 1], parent->children[i]); } it++; } } void Transformable::MoveDown(Layer *l) { if(l != nullptr) { auto it = l->GetAllObjects().begin(); for(int i = 0; i < l->GetAllObjects().size(); i++) { if((*it)->id == id) { if(i == l->GetAllObjects().size() - 1) return; std::swap(l->GetAllObjects()[i + 1], l->GetAllObjects()[i]); } it++; } return; } auto it = parent->children.begin(); for(int i = 0; i < parent->children.size(); i++) { if((*it)->id == id) { if(i == parent->children.size() - 1) return; std::swap(parent->children[i + 1], parent->children[i]); } it++; } } bool Transformable::IsEnabled() const { return _enabled; } void Transformable::SetEnabled(bool v) { if (_enabled != v) { _enabled = v; if (_enabled) OnEnable(); else OnDisable(); } } BehaviourScript *Transformable::AddBehaviourScript(BehaviourScript *script) { if (!script) return nullptr; const std::string key = typeid(*script).name(); components.emplace(key, script); script->SetBaseObject(this); script->Start(); return script; } BehaviourScript *Transformable::GetBehaviourScript(const string &name) const { auto it = components.find(name); return (it != components.end()) ? it->second : nullptr; } BehaviourScript *Transformable::GetBehaviourScriptAt(const int i) const { auto it = components.begin(); for (int j = 0; j < i; j++) { it++; } return (*it).second; } std::vector Transformable::GetAllBehaviourScripts(const string &name) const { std::vector res; auto it = components.begin(); while(it != components.end()) { if((*it).first == name) { res.push_back((*it).second); } } return res; } void Transformable::RemoveBehaviourScript(BehaviourScript *script) { for (auto it = components.begin(); it != components.end(); ++it) { if (it->second == script) { components.erase(it); break; } } } bool Transformable::HasBehaviourScript(const string &name) const { auto it = components.find(name); return it != components.end(); } void Transformable::Update() { for (auto& [name, script] : components) { if (script && script->IsEnabled()) script->OnUpdate(); } for (auto child : children) { child->Update(); } } void Transformable::Delete(Transformable *t) { objectEntries.erase(t->id); delete t; } void Transformable::Delete(const uuids::uuid id) { if(!Exists(id)) return; Transformable* t = objectEntries.at(id); objectEntries.erase(id); delete t; } void Transformable::HardDelete(Transformable *t, bool onlyThis) { //deleting children if(!onlyThis) for(auto child : t->children) { HardDelete(child); } //deleting atteched scripts for (auto& [_, script] : t->components) delete script; //deleting self Delete(t); } void Transformable::HardDelete(const uuids::uuid id, bool onlyThis) { if(!Exists(id)) return; Transformable* t = objectEntries.at(id); //deleting children if(!onlyThis) for(auto child : t->children) { HardDelete(child); } //deleting atteched scripts for (auto& [_, script] : t->components) delete script; //deleting self Delete(t); } void Transformable::DeleteAll() { auto it = objectEntries.begin(); for(int i = 0; i < objectEntries.size(); i++) { delete it->second; it++; } objectEntries.clear(); } bool Transformable::Exists(const uuids::uuid id) { auto it = objectEntries.find(id); return it != objectEntries.end(); } bool Transformable::operator==(const Transformable &other) const { return other.id == id; } bool Transformable::operator!=(const Transformable &other) const { return other.id != id; } void Transformable::OnEnable() { for (auto& [_, script] : components) if (script && script->IsEnabled()) script->OnEnable(); } void Transformable::OnDisable() { for (auto& [_, script] : components) if (script && script->IsEnabled()) script->OnDisable(); } int Transformable::GetTansformableCount() { return objectEntries.size(); } Transformable *Transformable::Find(string name) { for(auto obj : objectEntries) { if(obj.second->name == name) { return obj.second; } } return nullptr; } Transformable *Transformable::Find(uuids::uuid id) { for(auto obj : objectEntries) { if(obj.second->id == id) { return obj.second; } } return nullptr; } } // namespace TSE