470 lines
11 KiB
C++
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
|