kick
|
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 }