glm::vec3 TransformSystem::AbsoluteOrientationEuler(EntityWrapper entity)
{
    glm::vec3 orientation;

    while (entity.Valid()) {
        ComponentWrapper transform = entity["Transform"];
        orientation += (Field<glm::vec3>)transform["Orientation"];
        entity = entity.Parent();
    }

    return orientation;
}
glm::quat TransformSystem::AbsoluteOrientation(EntityWrapper entity)
{
    if (!entity.Valid()) {
        return glm::quat();
    }

    auto cacheIt = OrientationCache.find(entity);
    ComponentWrapper cTransform = entity["Transform"];
    ComponentWrapper::SubscriptProxy cTransformOrientation = cTransform["Orientation"];
    if (cacheIt != OrientationCache.end() && !cTransformOrientation.Dirty(DirtySetType::Transform)) {
        return cacheIt->second;
    } else {
        EntityWrapper parent = entity.Parent();
        // Calculate orientation
        glm::quat orientation = AbsoluteOrientation(parent) * glm::quat((const glm::vec3&)cTransformOrientation);
        // Cache it
        OrientationCache[entity] = orientation;
        RecalculatedOrientations++;
        // Unset dirty flag
        cTransformOrientation.SetDirty(DirtySetType::Transform, false);
        return orientation;
    }
}
glm::vec3 TransformSystem::AbsoluteScale(EntityWrapper entity)
{
    if (!entity.Valid()) {
        return glm::vec3(1.f);
    }

    auto cacheIt = ScaleCache.find(entity);
    ComponentWrapper cTransform = entity["Transform"];
    ComponentWrapper::SubscriptProxy cTransformScale = cTransform["Scale"];
    if (cacheIt != ScaleCache.end() && !cTransformScale.Dirty(DirtySetType::Transform)) {
        return cacheIt->second;
    } else {
        EntityWrapper parent = entity.Parent();
        // Calculate scale
        glm::vec3 scale = AbsoluteScale(parent) * (const glm::vec3&)cTransformScale;
        // Cache it
        ScaleCache[entity] = scale;
        RecalculatedPositions++;
        // Unset dirty flag
        cTransformScale.SetDirty(DirtySetType::Transform, false);
        return scale;
    }
}