195 lines
5.0 KiB
C++
195 lines
5.0 KiB
C++
// Copyright (c) 2022 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#include "Transform.hpp"
|
|
#include "scene/SceneItem.hpp"
|
|
#include "util/mathutils.hpp"
|
|
|
|
using namespace Dawn;
|
|
|
|
Transform::Transform(SceneItem *item) :
|
|
transformLocal(1.0f),
|
|
transformWorld(1.0f)
|
|
{
|
|
assertNotNull(item);
|
|
|
|
this->item = item;
|
|
this->updateLocalValuesFromLocalTransform();
|
|
}
|
|
|
|
void Transform::updateLocalValuesFromLocalTransform() {
|
|
glm::vec3 skew;
|
|
glm::vec4 perspective;
|
|
glm::decompose(
|
|
this->transformLocal,
|
|
this->localScale,
|
|
this->localRotation,
|
|
this->localPosition,
|
|
skew, perspective
|
|
);
|
|
}
|
|
|
|
void Transform::updateLocalTransformFromLocalValues() {
|
|
glm::mat4 translate = glm::translate(glm::mat4(1.0), this->localPosition);
|
|
glm::mat4 rotate = glm::mat4_cast(this->localRotation);
|
|
glm::mat4 scale = glm::scale(glm::mat4(1.0), this->localScale);
|
|
this->transformLocal = translate * rotate * scale;
|
|
this->updateWorldTransformFromLocalTransform();
|
|
}
|
|
|
|
void Transform::updateWorldTransformFromLocalTransform() {
|
|
auto parent = this->getParent();
|
|
if(parent != nullptr) {
|
|
auto newWorld = parent->getWorldTransform();
|
|
this->transformWorld = newWorld * transformLocal;
|
|
} else {
|
|
this->transformWorld = transformLocal;
|
|
}
|
|
}
|
|
|
|
void Transform::updateLocalTransformFromWorldTransform() {
|
|
glm::mat4 parentMat(1.0f);
|
|
auto parent = this->getParent();
|
|
if(parent != nullptr) parentMat = parent->getWorldTransform();
|
|
this->transformLocal = parentMat / this->transformWorld;
|
|
this->updateLocalValuesFromLocalTransform();
|
|
}
|
|
|
|
void Transform::updateChildrenTransforms() {
|
|
auto it = this->children.begin();
|
|
while(it != this->children.end()) {
|
|
(*it)->updateWorldTransformFromLocalTransform();
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void Transform::lookAt(glm::vec3 pos, glm::vec3 look) {
|
|
this->lookAt(pos, look, glm::vec3(0, 1, 0));
|
|
}
|
|
|
|
void Transform::lookAt(glm::vec3 pos, glm::vec3 look, glm::vec3 up) {
|
|
this->setWorldTransform(glm::lookAt(pos, look, up));
|
|
}
|
|
|
|
float_t Transform::lookAtPixelPerfect(
|
|
glm::vec3 position, glm::vec3 look, float_t viewportHeight, float_t fov
|
|
) {
|
|
float_t z = (
|
|
tanf((mathDeg2Rad(180.0f) - fov) / 2.0f) *
|
|
(viewportHeight/2.0f)
|
|
);
|
|
this->lookAt(glm::vec3(position.x, position.y, position.z + z), look);
|
|
return z;
|
|
}
|
|
|
|
glm::vec3 Transform::getLocalPosition() {
|
|
return this->localPosition;
|
|
}
|
|
|
|
void Transform::setLocalPosition(glm::vec3 position) {
|
|
this->localPosition = position;
|
|
this->updateLocalTransformFromLocalValues();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
glm::vec3 Transform::getLocalScale() {
|
|
return this->localScale;
|
|
}
|
|
|
|
void Transform::setLocalScale(glm::vec3 scale) {
|
|
this->localScale = scale;
|
|
this->updateLocalTransformFromLocalValues();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
glm::quat Transform::getLocalRotation() {
|
|
return this->localRotation;
|
|
}
|
|
|
|
void Transform::setLocalRotation(glm::quat rotation) {
|
|
this->localRotation = rotation;
|
|
this->updateLocalTransformFromLocalValues();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
|
|
glm::mat4 Transform::getLocalTransform() {
|
|
return this->transformLocal;
|
|
}
|
|
|
|
void Transform::setLocalTransform(glm::mat4 transform) {
|
|
this->transformLocal = transform;
|
|
|
|
this->updateLocalValuesFromLocalTransform();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
glm::vec3 Transform::getWorldPosition() {
|
|
return this->transformWorld[3];
|
|
}
|
|
|
|
glm::mat4 Transform::getWorldTransform() {
|
|
return this->transformWorld;
|
|
}
|
|
|
|
void Transform::setWorldTransform(glm::mat4 transform) {
|
|
this->transformWorld = transform;
|
|
this->updateLocalTransformFromWorldTransform();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
|
|
void Transform::setParent(Transform *parent) {
|
|
assertTrue(parent != this);
|
|
|
|
auto currentParent = this->getParent();
|
|
if(currentParent == parent) return;
|
|
|
|
if(currentParent != nullptr) {
|
|
auto it = currentParent->children.begin();
|
|
while(it != currentParent->children.end()) {
|
|
if(*it == this) {
|
|
currentParent->children.erase(it);
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
this->parent = parent;
|
|
if(parent != nullptr) parent->children.push_back(this);
|
|
|
|
this->updateLocalTransformFromWorldTransform();
|
|
this->updateChildrenTransforms();
|
|
this->eventTransformUpdated.invoke();
|
|
}
|
|
|
|
Transform * Transform::getParent() {
|
|
return this->parent;
|
|
}
|
|
|
|
bool_t Transform::isChildOf(Transform *parent) {
|
|
Transform *current = this->getParent();
|
|
while(current != nullptr) {
|
|
if(current == parent) return true;
|
|
current = current->getParent();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Transform::~Transform() {
|
|
this->setParent(nullptr);
|
|
|
|
auto it = this->children.begin();
|
|
while(it != this->children.end()) {
|
|
(*it)->setParent(nullptr);
|
|
++it;
|
|
}
|
|
} |