File Transform.cpp
File List > compo > Transform.cpp
Go to the documentation of this file
#include "Transform.h"
#include "xdz_math.h"
#include "xdz_matrix.h"
#include "glm/gtx/matrix_decompose.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/gtx/euler_angles.hpp"
#include "glm/gtx/rotate_vector.hpp"
#include "macros.h"
#include "operator.h"
inline glm::mat4 OffestTransform(const glm::mat4& in_m, const glm::vec3& in_v) {
glm::mat4 result(in_m);
LOOP(3)
result[3][i] += in_v[i];
return result;
}
bool Set1D(glm::vec3& _tar, float _1d, GLuint _dim);
void Transform::UseTranformComp(bool _enable, TransType _type)
{
if (_type & TransType::Position)
use_position = _enable;
if (_type & TransType::Rotation)
use_rotation = _enable;
if (_type & TransType::Scale)
use_scale = _enable;
}
Transform3D::Transform3D()
{
}
Transform3D::~Transform3D()
{
}
bool Transform3D::SetPos(const glm::vec3& pos)
{
if (o_position == pos) return false;
if (!use_position) return false;
is_TransF_changed = true;
o_position = pos;
return true;
}
bool Transform3D::SetPos1D(float _1d, GLuint _dim)
{
if (!use_position) return false;
return _set1D(o_position, _1d, _dim);
}
bool Transform3D::SetScale(const glm::vec3& scale)
{
if (o_scale == scale) return false;
if (!use_scale) return false;
is_TransF_changed = true;
o_scale = scale;
return true;
}
bool Transform3D::SetScale1D(float _1d, GLuint _dim)
{
if (!use_scale) return false;
return _set1D(o_scale, _1d, _dim);
}
bool Transform3D::SetRot(const glm::vec3& rot)
{
if (o_rot == rot) return false;
if (!use_rotation) return false;
is_TransF_changed = true;
o_rot = rot;
_updateDirections();
return true;
}
bool Transform3D::SetRot1D(float _1d, GLuint _dim)
{
if (!use_rotation) return false;
bool res = _set1D(o_rot, _1d, _dim);
if (!res) return false;
_updateDirections();
return true;
}
bool Transform3D::SetTrans(const glm::mat4& _trans, bool pos /*= true*/, bool rot /*= true*/, bool scl /*= true*/)
{
if (_trans == o_Transform)
return false;
glm::vec3 scale, position, _sk;
glm::quat rotation;
glm::vec4 _pers;
glm::decompose(_trans, scale, rotation, position, _sk, _pers);
if (pos) SetPos(position);
if (rot) SetRot(glm::degrees(glm::eulerAngles(rotation)));
if (scl) SetScale(scale);
if (pos && rot && scl) {
if (!(use_position && use_rotation && use_scale))
return false; // if there is at least one locked
if (o_parent_trans != nullptr) // o_Transform is the global transform not local
return false;
o_Transform = _trans;
is_TransF_changed = false;
is_invTransF_changed = true;
is_Uniform_changed = true;
is_invUniform_changed = true;
}
return true;
}
void Transform3D::Trans(const glm::mat4& _trans)
{
is_invTransF_changed = true;
is_invUniform_changed = true;
o_Transform = _trans * o_Transform;
}
void Transform3D::Move(const glm::vec3& d_pos)
{
assert(false);
}
void Transform3D::Spin(const glm::vec3& anch, const glm::vec3& axis, const float& angle)
{
assert(false);
}
void Transform3D::Spin(const glm::vec3& anch, const glm::vec2& angle, bool global_up/* = true*/)
{
if (angle == glm::vec2(0))
return;
o_position -= anch;
o_position = global_up ? glm::rotateZ(o_position, angle.x) : glm::rotate(o_position, angle.y, o_dir_up);
SetRot(o_rot + glm::vec3(0.0f, 0.0f, glm::degrees(angle.x)));
o_position = glm::rotate(o_position, angle.y, o_dir_right);
SetRot(o_rot + glm::vec3(glm::degrees(angle.y), 0.0f, 0.0f));
o_position += anch;
}
void Transform3D::LookAt(const glm::vec3& tar, const glm::vec3& up)
{
glm::mat4 trans = xdzm::lookAt(o_position, tar, up);
//glm::vec3 dir = glm::normalize(cam_tar - o_position);
SetTrans(trans, false, true, false);
}
void Transform3D::SetParent(Transform3D* _p_trans, bool _keep_offset /*= true*/)
{
ApplyTransform();
_p_trans->ApplyTransform();
_p_trans->GetInvTransform();
o_parent_trans = _p_trans;
_p_trans->o_child_trans = this;
if (!_keep_offset) return;
// if self.trans = B =A * D, parent.trans = A, then D = A^-1 * B
glm::mat4 D = _p_trans->o_InvTransform * o_Transform;
SetTrans(D);
}
void Transform3D::UnsetParent(bool _keep_offset /*= true*/)
{
}
bool Transform3D::_set1D(glm::vec3& _tar, float _1d, GLuint _dim)
{
if (_dim < 0 || _dim > 2) return false;
if (_tar[_dim] == _1d) return false;
_tar[_dim] = _1d;
is_TransF_changed = true;
return true;
}
void Transform3D::_updateDirections()
{
glm::mat4 rot_mat = glm::mat4_cast(glm::qua(glm::radians(o_rot)));
o_dir_up = rot_mat * glm::vec3(0.0f, 1.0f, 0.0f);
o_dir_right = rot_mat * glm::vec3(1.0f, 0.0f, 0.0f);
}
bool Transform3D::ApplyTransform(bool _forced /*= false*/)
{
if (!is_TransF_changed && !_forced) return false;
glm::mat4 rot_mat = glm::mat4_cast(glm::qua(glm::radians(o_rot)));
o_Transform = rot_mat * glm::scale(glm::mat4(1), o_scale);
o_Transform = OffestTransform(o_Transform, o_position);
is_invTransF_changed = true;
is_TransF_changed = false;
is_Uniform_changed = true;
return true;
}
bool Transform3D::ApplyAllTransform()
{
if (GetParentTransPtr() != nullptr) { // skip all child node
return false;
}
Transform3D* tar_ptr = this;
glm::mat4 post_trans = glm::mat4(1);
bool is_changed = false;
do {
is_changed |= tar_ptr->is_TransF_changed;
if (is_changed) {
tar_ptr->ApplyTransform(true);
tar_ptr->o_Transform = post_trans * tar_ptr->o_Transform;
}
tar_ptr->is_Uniform_changed |= is_changed;
post_trans = tar_ptr->o_Transform;
if (tar_ptr->GetChildTransPtr() == nullptr)
break;
else
tar_ptr = tar_ptr->GetChildTransPtr();
} while (true);
return true;
}
/*std::unordered_map<int, int, float> */
bool Transform3D::GetInvTransform() const
{
if (!is_invTransF_changed) return false;
glm::mat3 rot = glm::mat3(o_Transform);
glm::vec3 scale;
LOOP(3) {
scale[i] = glm::length(rot[i]);
rot[i] /= scale[i];
}
const glm::mat4 inv_loc = glm::translate(glm::mat4(1.0f), -glm::vec3(o_Transform[3]));
const glm::mat4 inv_rot = glm::mat4(glm::transpose(rot));
const glm::mat4 inv_scl = glm::scale(glm::mat4(1.0f), 1.0f / scale);
o_InvTransform = inv_scl * inv_rot * inv_loc;
is_invTransF_changed = false;
is_invUniform_changed = true;
return true;
}
int Transform3D::_debug() const
{
#ifdef _DEBUG
std::cout << o_rot << ", ";
std::cout << o_dir_up << ", ";
std::cout << o_dir_right << ", ";
DEBUG("________________");
#endif // _DEBUG
return 0;
}
Transform2D::Transform2D()
{
}
Transform2D::~Transform2D()
{
}
bool Transform2D::SetPos(const glm::vec2& pos)
{
if (pos == o_position) return false;
o_position = pos;
is_TransF_changed = true;
return true;
}
bool Transform2D::SetScale(const glm::vec2& scale)
{
if (scale == o_scale) return false;
o_scale = scale;
is_TransF_changed = true;
return true;
}
bool Transform2D::SetRot(float rot)
{
if (rot == o_rot) return false;
o_rot = rot;
is_TransF_changed = true;
return true;
}
void Transform2D::Trans(const glm::mat3& _trans)
{
}
void Transform2D::Move(const glm::vec2& d_pos)
{
if (d_pos != glm::vec2(0))
SetPos(o_position + d_pos);
}
void Transform2D::Spin(float angle)
{
if (angle != 0)
SetRot(o_rot + angle);
}
void Transform2D::Zoom(const glm::vec2& scale)
{
if (scale != glm::vec2(0) && scale != glm::vec2(1))
SetScale(o_scale * scale);
}
void Transform2D::Zoom(float scale)
{
if (scale != 1 && scale != 0)
SetScale(o_scale * scale);
}
void Transform2D::LookAt(const glm::vec2& tar)
{
}
void Transform2D::SetParent(Transform2D* _p_trans, bool _keep_offset /*= true*/)
{
}
void Transform2D::UnsetParent(bool _keep_offset /*= true*/)
{
}
bool Transform2D::ApplyTransform(bool _forced /*= false*/)
{
if (!is_TransF_changed) return false;
LOOP(2) {
o_Transform[i][i] = o_scale[i];
o_Transform[2][i] = o_position[i] * o_scale[i];
}
o_Transform[2][2] = 1.0f;
is_TransF_changed = false;
is_invTransF_changed = true;
return true;
}
bool Transform2D::ApplyAllTransform()
{
return true;
}
bool Transform2D::GetInvTransform() const
{
if (!is_invTransF_changed) return false;
LOOP(2) {
o_InvTransform[i][i] = 1 / o_scale[i];
o_InvTransform[2][i] = -o_position[i];
}
o_InvTransform[2][2] = 1.0f;
is_invTransF_changed = false;
return true;
}
int Transform2D::_debug() const
{
#ifdef _DEBUG
std::cout << o_rot;
DEBUG("________________");
#endif // _DEBUG
return 0;
}