Files
TSE/TSE_Core/src/elements/Transformable.cpp
2026-01-17 13:48:25 +01:00

470 lines
11 KiB
C++

#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 *> &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<BehaviourScript *> Transformable::GetAllBehaviourScripts(const string &name) const
{
std::vector<BehaviourScript *> 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