kick
/Users/morten/Programmering/cpp/kick/src/kick/scene/transform.cpp
00001 //
00002 //  transform.cpp
00003 //  KickCPP
00004 //
00005 //  Created by morten on 8/13/13.
00006 //  Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved.
00007 //
00008 
00009 #include "kick/scene/transform.h"
00010 #include "kick/math/glm_ext.h"
00011 #include <algorithm>
00012 #include <iostream>
00013 
00014 using namespace glm;
00015 
00016 namespace kick {
00017     Transform::Transform(GameObject *gameObject)
00018     :Component(gameObject){
00019     }
00020     
00021     void Transform::markGlobalDirty(){
00022         mDirty.global = 1;
00023         mDirty.globalInv = 1;
00024         mDirty.globalPos = 1;
00025         mDirty.globalRot = 1;
00026         for (auto c : mChildren){
00027             c->markGlobalDirty();
00028         }
00029     }
00030     
00031     void Transform::markLocalDirty(){
00032         mDirty.local = 1;
00033         mDirty.localInv = 1;
00034         markGlobalDirty();
00035     }
00036     
00037     void Transform::setPosition(glm::vec3 position_){
00038         assert(!glm::any(glm::isnan(position_)));
00039         if (!mParent){
00040             setLocalPosition(position_);
00041             return;
00042         }
00043         vec3 currentPosition = position();
00044         setLocalPosition(currentPosition - position_);
00045         markLocalDirty();
00046     }
00047     
00048     glm::vec3 Transform::position(){
00049         if (!mParent){
00050             return mLocalPosition;
00051         }
00052         if (mDirty.globalPos){
00053             auto pos = globalMatrix() * vec4(0,0,0,1);
00054             mGlobalPosition = vec3(pos);
00055         }
00056         return mGlobalPosition;
00057     }
00058     
00059     void Transform::setLocalPosition(glm::vec3 position){
00060         assert(!glm::any(glm::isnan(position)));
00061         mLocalPosition = position;
00062         markLocalDirty();
00063     }
00064     
00065     glm::vec3 Transform::localPosition(){
00066         return mLocalPosition;
00067     }
00068     
00069     void Transform::setLocalRotationEuler(glm::vec3 angles){
00070         assert(!glm::any(glm::isnan(angles)));
00071         mat4 rot = yawPitchRoll(angles.y, angles.x, angles.z);
00072         mLocalRotationQuat = quat_cast(rot);
00073         markLocalDirty();
00074     }
00075     
00076     glm::vec3 Transform::localRotationEuler(){
00077         return eulerAngles(mLocalRotationQuat);
00078     }
00079     
00080     void Transform::setRotationEuler(glm::vec3 angles){
00081         assert(!glm::any(glm::isnan(angles)));
00082         mat4 rot = yawPitchRoll(angles.y, angles.x, angles.z);
00083         setRotation(quat_cast(rot));
00084     }
00085     
00086     glm::vec3 Transform::rotationEuler(){
00087         return eulerAngles(rotation());
00088     }
00089     
00090     void Transform::setRotation(glm::quat rot){
00091         assert(!glm::isnan(rot.w) && !glm::isnan(rot.x) && !glm::isnan(rot.y) && !glm::isnan(rot.z));
00092         if (mParent == nullptr ||
00093                 mParent->mGlobalRotationQuat == glm::quat{1,0,0,0}){ // if parent is identity rotation
00094             setLocalRotation(rot);
00095         } else {
00096             quat diff = conjugate(rot) * rotation();
00097             setLocalRotation(mLocalRotationQuat * diff);
00098         }
00099     }
00100     
00101     glm::quat Transform::rotation(){
00102         if (mParent == nullptr){
00103             return mLocalRotationQuat;
00104         }
00105         if (mDirty.globalRot){
00106             mGlobalRotationQuat = mLocalRotationQuat;
00107             auto parentIterator = this->mParent;
00108             while (parentIterator != nullptr){
00109                 mGlobalRotationQuat = parentIterator->mLocalRotationQuat * mGlobalRotationQuat;
00110                 parentIterator = parentIterator->mParent;
00111             }
00112         }
00113         return mGlobalRotationQuat;
00114     }
00115     
00116     void Transform::setLocalRotation(glm::quat rot){
00117         assert(!glm::isnan(rot.w) && !glm::isnan(rot.x) && !glm::isnan(rot.y) && !glm::isnan(rot.z));
00118         mLocalRotationQuat = rot;
00119         markLocalDirty();
00120     }
00121     
00122     glm::quat Transform::localRotation(){
00123         return mLocalRotationQuat;
00124     }
00125     
00126     void Transform::setLocalScale(glm::vec3 scale){
00127         assert(!glm::any(glm::isnan(scale)));
00128         mLocalScale = scale;
00129         markLocalDirty();
00130     }
00131     
00132     glm::vec3 Transform::localScale(){
00133         return mLocalScale;
00134     }
00135     
00136     void Transform::setParent(std::shared_ptr<Transform> parent){
00137         if (parent && parent.get() == this){
00138             return;
00139         }
00140         if (this->mParent){
00141             auto pos = find(this->mParent->mChildren.begin(),this->mParent->mChildren.end(), std::dynamic_pointer_cast<Transform>(shared_from_this()));
00142             this->mParent->mChildren.erase(pos);
00143         }
00144         this->mParent = parent;
00145         if (parent){
00146             parent->mChildren.push_back(std::dynamic_pointer_cast<Transform>( shared_from_this()));
00147 
00148             // search for circularity
00149             while (parent != nullptr){
00150                 if (parent->mParent && parent->mParent.get() == this){ // circularity found - break
00151                     parent->setParent(std::shared_ptr<Transform>());
00152                 }
00153                 parent = parent->mParent;
00154             }
00155         }
00156     }
00157     
00158     glm::mat4 Transform::localTRSInverse(){
00159         if (mDirty.localInv){
00160             mLocalMatrixInverse = kick::TRSInverse(mLocalPosition, mLocalRotationQuat, mLocalScale);
00161             mDirty.localInv = false;
00162         }
00163         return mLocalMatrixInverse;
00164     }
00165     
00166     glm::mat4 Transform::globalTRSInverse(){
00167         if (mDirty.globalInv){
00168             mGlobalMatrixInverse = localTRSInverse();
00169             auto transformIterator = mParent;
00170             while (transformIterator){
00171                 mGlobalMatrixInverse = mGlobalMatrixInverse * transformIterator->localTRSInverse();
00172                 transformIterator = transformIterator->mParent;
00173             }
00174             mDirty.globalInv = false;
00175         }
00176         return mGlobalMatrixInverse;
00177     }
00178 
00179     void Transform::lookAt(vec3 center, glm::vec3 up){
00180         assert(!glm::any(glm::isnan(up)));
00181         vec3 eye = position();
00182         assert(glm::length(eye - center) > glm::epsilon<float>());
00183         auto rotation = kick::lookAt(eye, center, up);
00184         setRotation(conjugate(rotation));
00185     }
00186 
00187     void Transform::lookAt(Transform *target, glm::vec3 up){
00188         vec3 center = target->position();
00189         lookAt(center, up);
00190     }
00191     
00192     glm::mat4 Transform::localMatrix(){
00193         if (mDirty.local) {
00194             mLocalMatrix = kick::TRS(mLocalPosition, mLocalRotationQuat, mLocalScale);
00195             mDirty.local = false;
00196         }
00197         return mLocalMatrix;
00198     }
00199     
00200     glm::mat4 Transform::globalMatrix(){
00201         if (mDirty.global) {
00202             mGlobalMatrix = localMatrix();
00203             
00204             auto transformIterator = mParent;
00205             while (transformIterator) {
00206                 mGlobalMatrix = transformIterator->localMatrix() * mGlobalMatrix;
00207                 transformIterator  = transformIterator->mParent;
00208             }
00209             mDirty.global = false;
00210         }
00211         return mGlobalMatrix;
00212     }
00213     
00214     TransformIter Transform::begin(){
00215         return mChildren.begin();
00216     }
00217     
00218     TransformIter Transform::end(){
00219         return mChildren.end();
00220     }
00221     
00222     ConstTransformIter Transform::begin() const {
00223         return mChildren.begin();
00224     }
00225     
00226     ConstTransformIter Transform::end() const {
00227         return mChildren.end();
00228     }
00229 
00230     std::shared_ptr<Transform> Transform::root() {
00231                 if (!mParent){
00232                         return std::dynamic_pointer_cast<Transform>(shared_from_this());
00233                 }
00234                 auto t = mParent;
00235                 while (t->mParent) {
00236                         t = t->mParent;
00237                 }
00238                 return t;
00239         }
00240 
00241     std::shared_ptr<Transform> Transform::parent() {
00242         return mParent;
00243     }
00244 
00245     vec3 Transform::forward() {
00246         return mat3_cast(rotation()) * vec3(0,0,-1);
00247     }
00248 
00249     vec3 Transform::up() {
00250         return mat3_cast(rotation()) * vec3(0,1,0);
00251     }
00252 
00253     vec3 Transform::right() {
00254         return mat3_cast(rotation()) * vec3(1,0,0);
00255     }
00256 }
 All Classes Functions Variables