From 4a73b0773b77d901a215fea1f8de3ab14a475597 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:56:05 -0800 Subject: [PATCH] first take at the Transform encapsulating a transform matrix --- interface/src/gpu/Transform.cpp | 109 ++++++++++++++++++++++++++++++ interface/src/gpu/Transform.h | 113 ++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 interface/src/gpu/Transform.cpp create mode 100644 interface/src/gpu/Transform.h diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp new file mode 100644 index 0000000000..cb1607dd0b --- /dev/null +++ b/interface/src/gpu/Transform.cpp @@ -0,0 +1,109 @@ +// +// Transform.cpp +// interface/src/gpu +// +// Created by Sam Gateau on 11/4/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Transform.h" + +#include + +using namespace gpu; + +Transform::Transform() : + _translation(0), + _rotation(1.f, 0, 0, 0), + _scale(1.f), + _flags(1) // invalid cache +{ +} +Transform::Transform(const Mat4& raw) { + evalFromRawMatrix(raw); +} + +void Transform::updateCache() const { + if (isCacheInvalid()) { + glm::mat3x3 rot = glm::mat3_cast(_rotation); + + if ((_scale.x != 1.f) || (_scale.y != 1.f) || (_scale.z != 1.f)) { + rot[0] *= _scale.x; + rot[1] *= _scale.y; + rot[2] *= _scale.z; + } + + _matrix[0] = Vec4(rot[0], 0.f); + _matrix[1] = Vec4(rot[1], 0.f); + _matrix[2] = Vec4(rot[2], 0.f); + + _matrix[3] = Vec4(_translation, 0.f); + + validCache(); + } +} + +void Transform::localTranslate( Vec3 const & translation) { + Vec3 tt = glm::rotate(_rotation, translation); + _translation += tt * _scale; +} + +Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { + updateCache(); + result = _matrix; + result[3] = Vec4(_translation - origin, 0.f); + return result; +} + +void Transform::evalFromRawMatrix(const Mat4& matrix) { + if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { + setTranslation(Vec3(matrix[3])); + + Mat3 matRS = Mat3(matrix); + + Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); + + matRS[0] *= 1/scale.x; + matRS[1] *= 1/scale.y; + matRS[2] *= 1/scale.z; + + setRotation(glm::quat_cast(matRS)); + setScale(scale); + } +} + +Transform& Transform::evalInverseTranspose(Transform& result) { + result.setTranslation(-_translation); + result.setRotation(-_rotation); + + if (isScaling()) { + result.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); + } + return result; +} + +Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) { + right.updateCache(); + left.updateCache(); + + result.setTranslation(Vec3(left.getMatrix() * Vec4(right.getTranslation(), 1.f))); + + Mat4 mat = left.getMatrix() * right.getMatrix(); + Mat3 matRS = Mat3(mat); + + Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2])); + + matRS[0] *= 1/scale.x; + matRS[1] *= 1/scale.y; + matRS[2] *= 1/scale.z; + + result.setRotation(glm::quat_cast(matRS)); + result.setScale(scale); + + return result; +} + + diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h new file mode 100644 index 0000000000..e1e3f574e9 --- /dev/null +++ b/interface/src/gpu/Transform.h @@ -0,0 +1,113 @@ +// +// Transform.h +// interface/src/gpu +// +// Created by Sam Gateau on 11/4/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Transform_h +#define hifi_gpu_Transform_h + +#include +#include "InterfaceConfig.h" + +#include "gpu/Format.h" + + +#include + +#include +#include +#include + +#include + +namespace gpu { + +class Transform { +public: + typedef glm::mat4 Mat4; + typedef glm::mat3 Mat3; + typedef glm::vec4 Vec4; + typedef glm::vec3 Vec3; + typedef glm::vec2 Vec2; + typedef glm::quat Quat; + + Transform(); + Transform(const Mat4& raw); + ~Transform() {} + + void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; } + const Vec3& getTranslation() const { return _translation; } + void parentTranslate(const Vec3& translation) { _translation += translation; } + void localTranslate( Vec3 const & translation); + + void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = rotation; } + const Quat& getRotation() const { return _rotation; } + + void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); } + void setScale(float scale) { invalidCache(); flagUniformScaling(); _scale = Vec3(scale); } + void setScale(const Vec3& scale) { invalidCache(); flagNonUniformScaling(); _scale = scale; } + const Vec3& getScale() const { return _scale; } + + const Mat4& getMatrix() const { updateCache(); return _matrix; } + + Mat4& evalRelativeTransform(Mat4& result, const Vec3& origin); + + Transform& evalInverseTranspose(Transform& result); + void evalFromRawMatrix(const Mat4& matrix); + + static Transform& mult( Transform& result, const Transform& left, const Transform& right); + + bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } +protected: + + enum Flag { + FLAG_CACHE_INVALID = 0, + + FLAG_TRANSLATION, + FLAG_ROTATION, + FLAG_UNIFORM_SCALING, + FLAG_NON_UNIFORM_SCALING, + FLAG_SHEARING, + + FLAG_PROJECTION, + + NUM_FLAGS, + }; + + typedef std::bitset Flags; + + + // TRS + Vec3 _translation; + Quat _rotation; + Vec3 _scale; + + mutable Flags _flags; + + // Cached transform + mutable Mat4 _matrix; + bool isCacheInvalid() const { return _flags[FLAG_CACHE_INVALID]; } + void validCache() const { _flags.set(FLAG_CACHE_INVALID, false); } + void invalidCache() const { _flags.set(FLAG_CACHE_INVALID, true); } + + void flagTranslation() { _flags.set(FLAG_TRANSLATION, true); } + void flagRotation() { _flags.set(FLAG_ROTATION, true); } + + void flagNoScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } + void flagUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, true); _flags.set(FLAG_NON_UNIFORM_SCALING, false); } + void flagNonUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, true); } + + void updateCache() const; +}; + +typedef QSharedPointer< Transform > TransformPointer; + +}; + + +#endif