T3DTransform.cpp
Engine/source/T3D/sceneComponent/T3DTransform.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "T3DTransform.h" 25#include "math/mPoint.h" 26#include "math/mQuat.h" 27 28//--------------------------------------------------------- 29// T3DTransform 30//--------------------------------------------------------- 31 32void Transform3D::setParentTransform(Transform3D * parent) 33{ 34 if (_parentTransform == parent) 35 return; 36 _flags |= Transform3D::ParentDirty; 37 _parentTransform = parent; 38 if (_dirtyListener != NULL) 39 _dirtyListener->onTransformDirty(); 40} 41 42bool Transform3D::hasObjectScale() const 43{ 44 if (hasLocalScale()) 45 return true; 46 47 // check all parent transforms except last for scale 48 Transform3D * walk = _parentTransform; 49 while (walk != NULL && walk->_parentTransform != NULL) 50 { 51 if (walk->hasLocalScale()) 52 return true; 53 walk = walk->getParentTransform(); 54 } 55 return false; 56} 57 58bool Transform3D::hasWorldScale() const 59{ 60 if (hasLocalScale()) 61 return true; 62 63 // check all parent transforms for scale 64 Transform3D * walk = _parentTransform; 65 while (walk != NULL) 66 { 67 if (walk->hasLocalScale()) 68 return true; 69 walk = walk->getParentTransform(); 70 } 71 return false; 72} 73 74void Transform3D::setWorldMatrix(const MatrixF & world) 75{ 76 if (_parentTransform != NULL) 77 { 78 MatrixF parentMatrix; 79 _parentTransform->getWorldMatrix(parentMatrix, true); 80 MatrixF parentMatrixInv = parentMatrix; 81 parentMatrixInv.inverse(); 82 MatrixF localMat; 83 localMat = parentMatrixInv * world; 84 setLocalMatrix(localMat); 85 } 86 else 87 setLocalMatrix(world); 88} 89 90void Transform3D::setObjectMatrix(const MatrixF & objMatrix) 91{ 92 if (_parentTransform != NULL) 93 { 94 MatrixF parentMatrix; 95 _parentTransform->getObjectMatrix(parentMatrix, true); 96 MatrixF parentMatrixInv = parentMatrix; 97 parentMatrixInv.inverse(); 98 MatrixF localMat; 99 localMat = parentMatrixInv * objMatrix; 100 setLocalMatrix(localMat); 101 } 102 else 103 setLocalMatrix(objMatrix); 104} 105 106bool Transform3D::isChildOf(Transform3D * parent, bool recursive) const 107{ 108 if (_parentTransform != NULL) 109 { 110 if (_parentTransform == parent) 111 return true; 112 else if (recursive) 113 return _parentTransform->isChildOf(parent, true); 114 else 115 return false; 116 } 117 else 118 { 119 return false; 120 } 121} 122 123//--------------------------------------------------------- 124// Transform3DInPlace 125//--------------------------------------------------------- 126 127Point3F Transform3DInPlace::getPosition() const 128{ 129 return _position; 130} 131 132void Transform3DInPlace::setPosition(const Point3F & position) 133{ 134 _position = position; 135 _flags |= Transform3D::LocalPositionDirty; 136 if (_dirtyListener != NULL) 137 _dirtyListener->onTransformDirty(); 138} 139 140QuatF Transform3DInPlace::getRotation() const 141{ 142 return _rotation; 143} 144 145void Transform3DInPlace::setRotation(const QuatF & rotation) 146{ 147 _rotation = rotation; 148 _flags |= Transform3D::LocalRotationDirty; 149 if (_dirtyListener != NULL) 150 _dirtyListener->onTransformDirty(); 151} 152 153Point3F Transform3DInPlace::getScale() const 154{ 155 return _scale; 156} 157 158void Transform3DInPlace::setScale(const Point3F & scale) 159{ 160 _scale = scale; 161 _flags |= Transform3D::LocalScaleDirty; 162 if (_dirtyListener != NULL) 163 _dirtyListener->onTransformDirty(); 164} 165 166void Transform3DInPlace::getWorldMatrix(MatrixF & worldMat, bool includeLocalScale) const 167{ 168 if (_parentTransform == NULL) 169 getLocalMatrix(worldMat, includeLocalScale); 170 else 171 { 172 MatrixF localMat, parentMat; 173 getLocalMatrix(localMat, includeLocalScale); 174 _parentTransform->getWorldMatrix(parentMat, true); 175 worldMat = parentMat * localMat; 176 } 177} 178 179void Transform3DInPlace::getObjectMatrix(MatrixF & objectMat, bool includeLocalScale) const 180{ 181 if (_parentTransform == NULL) 182 objectMat = MatrixF::smIdentity; 183 else if (_parentTransform->getParentTransform() == NULL) 184 getLocalMatrix(objectMat, includeLocalScale); 185 else 186 { 187 MatrixF localMat, parentMat; 188 getLocalMatrix(localMat, includeLocalScale); 189 _parentTransform->getObjectMatrix(parentMat, true); 190 objectMat = parentMat * localMat; 191 } 192} 193 194void Transform3DInPlace::getLocalMatrix(MatrixF & localMat, bool includeLocalScale) const 195{ 196 _rotation.setMatrix(&localMat); 197 localMat.setColumn(3,_position); 198 if (includeLocalScale) 199 localMat.scale(_scale); 200} 201 202void Transform3DInPlace::setLocalMatrix(const MatrixF & localMat) 203{ 204 _rotation.set(localMat); 205 _position = localMat.getPosition(); 206 _scale = localMat.getScale(); 207 _flags |= Transform3D::LocalScaleDirty | Transform3D::LocalRotationDirty | Transform3D::LocalPositionDirty; 208 if (_dirtyListener != NULL) 209 _dirtyListener->onTransformDirty(); 210} 211 212//--------------------------------------------------------- 213// TSTransform3D 214//--------------------------------------------------------- 215 216TSTransform3D::TSTransform3D(TSShapeInstance * si, S32 nodeIndex) 217{ 218 _shapeInstance = si; 219 _nodeIndex = nodeIndex; 220 AssertFatal(_nodeIndex >= 0 && _nodeIndex < _shapeInstance->mNodeTransforms.size(), "TSTransform3D nodeIndex out of range"); 221} 222 223Point3F TSTransform3D::getPosition() const 224{ 225 if (!doHandleLocal()) 226 { 227 MatrixF mat; 228 return getTSLocal(mat).getPosition(); 229 } 230 return _position; 231} 232 233void TSTransform3D::setPosition(const Point3F & position) 234{ 235 setHandleLocal(true); 236 _position = position; 237 _flags |= Transform3D::LocalPositionDirty; 238 if (_dirtyListener != NULL) 239 _dirtyListener->onTransformDirty(); 240} 241 242QuatF TSTransform3D::getRotation() const 243{ 244 if (!doHandleLocal()) 245 { 246 MatrixF mat; 247 return QuatF(getTSLocal(mat)); 248 } 249 return _rotation; 250} 251void TSTransform3D::setRotation(const QuatF & rotation) 252{ 253 setHandleLocal(true); 254 _rotation = rotation; 255 _flags |= Transform3D::LocalRotationDirty; 256 if (_dirtyListener != NULL) 257 _dirtyListener->onTransformDirty(); 258} 259 260Point3F TSTransform3D::getScale() const 261{ 262 if (!doHandleLocal()) 263 { 264 MatrixF mat; 265 return getTSLocal(mat).getScale(); 266 } 267 return _scale; 268} 269void TSTransform3D::setScale(const Point3F & scale) 270{ 271 setHandleLocal(true); 272 _scale = scale; 273 _flags |= Transform3D::LocalScaleDirty; 274 if (_dirtyListener != NULL) 275 _dirtyListener->onTransformDirty(); 276} 277 278void TSTransform3D::getWorldMatrix(MatrixF & worldMat, bool includeLocalScale) const 279{ 280 _shapeInstance->animate(); 281 if (_parentTransform == NULL) 282 { 283 worldMat = _shapeInstance->mNodeTransforms[_nodeIndex]; 284 } 285 else 286 { 287 MatrixF parentMat; 288 _parentTransform->getWorldMatrix(parentMat, true); 289 worldMat = parentMat * _shapeInstance->mNodeTransforms[_nodeIndex]; 290 } 291} 292 293void TSTransform3D::getObjectMatrix(MatrixF & objectMat, bool includeLocalScale) const 294{ 295 if (_parentTransform == NULL) 296 objectMat = MatrixF::smIdentity; 297 else if (_parentTransform->getParentTransform() == NULL) 298 { 299 _shapeInstance->animate(); 300 objectMat = _shapeInstance->mNodeTransforms[_nodeIndex]; 301 } 302 else 303 { 304 _shapeInstance->animate(); 305 306 MatrixF parentMat; 307 _parentTransform->getObjectMatrix(parentMat, true); 308 objectMat = parentMat * _shapeInstance->mNodeTransforms[_nodeIndex]; 309 } 310} 311 312void TSTransform3D::getLocalMatrix(MatrixF & localMat, bool includeLocalScale) const 313{ 314 if (doHandleLocal()) 315 { 316 _rotation.setMatrix(&localMat); 317 localMat.setPosition(_position); 318 if (includeLocalScale) 319 localMat.scale(_scale); 320 } 321 else 322 { 323 _shapeInstance->animate(); 324 localMat = _shapeInstance->mNodeTransforms[_nodeIndex]; 325 if (!includeLocalScale && (_flags & Transform3D::LocalHasScale) != Transform3D::None) 326 { 327 // reverse any scale on matrix -- this is a inconvenient, but not a common case 328 Point3F scale = localMat.getScale(); 329 scale.x = 1.0f / scale.x; 330 scale.y = 1.0f / scale.y; 331 scale.z = 1.0f / scale.z; 332 localMat.scale(scale); 333 } 334 } 335} 336 337void TSTransform3D::setLocalMatrix(const MatrixF & localMatrix) 338{ 339 setHandleLocal(true); 340 _position = localMatrix.getPosition(); 341 _rotation.set(localMatrix); 342 _scale = localMatrix.getScale(); 343 _flags |= Transform3D::LocalScaleDirty | Transform3D::LocalRotationDirty | Transform3D::LocalPositionDirty; 344 if (_dirtyListener != NULL) 345 _dirtyListener->onTransformDirty(); 346} 347 348MatrixF & TSTransform3D::getTSLocal(MatrixF & mat) const 349{ 350 _shapeInstance->animate(); 351 352 // if node has no parent, easy enough to just grab the matrix of the node 353 int parentIdx = _shapeInstance->getShape()->nodes[_nodeIndex].parentIndex; 354 if (parentIdx < 0) 355 { 356 return _shapeInstance->mNodeTransforms[_nodeIndex]; 357 } 358 359 // has parent, local is transform from this node to parent so get local matrix the hard way 360 MatrixF parentMat = _shapeInstance->mNodeTransforms[parentIdx]; 361 parentMat.inverse(); 362 mat = parentMat * _shapeInstance->mNodeTransforms[_nodeIndex]; 363 return mat; 364} 365 366void TSTransform3D::setHandleLocal(bool handleLocal) 367{ 368 if (handleLocal == doHandleLocal()) 369 return; 370 371 if (handleLocal) 372 { 373 _position = getPosition(); 374 _rotation = getRotation(); 375 _scale = getScale(); 376 _shapeInstance->setNodeAnimationState(_nodeIndex, 0, this); 377 } 378 else 379 _shapeInstance->setNodeAnimationState(_nodeIndex, 0); 380 _flags ^= TSTransform3D::HandleLocal; 381} 382 383void TSTransform3D::setNodeTransform(TSShapeInstance * si, S32 nodeIndex, MatrixF & localTransform) 384{ 385 AssertFatal(si == _shapeInstance,"TSTransform3D hooked up to wrong shape."); 386 getLocalMatrix(localTransform, true); 387} 388