00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 00006 00007 Copyright © 2000-2002 The OGRE Team 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 #include "OgreStableHeaders.h" 00026 #include "OgreNode.h" 00027 00028 #include "OgreException.h" 00029 #include "OgreMath.h" 00030 00031 // Dependencies on render-related types due to ability to render node 00032 #include "OgreMaterialManager.h" 00033 #include "OgreMeshManager.h" 00034 #include "OgreMesh.h" 00035 #include "OgreSubMesh.h" 00036 #include "OgreCamera.h" 00037 00038 namespace Ogre { 00039 00040 unsigned long Node::msNextGeneratedNameExt = 1; 00041 //----------------------------------------------------------------------- 00042 Node::Node() 00043 { 00044 mParent = 0; 00045 mOrientation = mInitialOrientation = mDerivedOrientation = Quaternion::IDENTITY; 00046 mPosition = mInitialPosition = mDerivedPosition = Vector3::ZERO; 00047 mScale = mInitialScale = mDerivedScale = Vector3::UNIT_SCALE; 00048 mInheritScale = true; 00049 mParentNotified = false ; 00050 00051 // Generate a name 00052 static char temp[64]; 00053 sprintf(temp, "Unnamed_%lu", msNextGeneratedNameExt++); 00054 mName = temp; 00055 mAccumAnimWeight = 0.0f; 00056 00057 needUpdate(); 00058 00059 } 00060 //----------------------------------------------------------------------- 00061 Node::Node(const String& name) 00062 { 00063 mName = name; 00064 mParent = 0; 00065 mOrientation = mInitialOrientation = mDerivedOrientation = Quaternion::IDENTITY; 00066 mPosition = mInitialPosition = mDerivedPosition = Vector3::ZERO; 00067 mScale = mInitialScale = mDerivedScale = Vector3::UNIT_SCALE; 00068 mInheritScale = true; 00069 mAccumAnimWeight = 0.0f; 00070 mParentNotified = false ; 00071 00072 needUpdate(); 00073 00074 } 00075 00076 //----------------------------------------------------------------------- 00077 Node::~Node() 00078 { 00079 } 00080 00081 //----------------------------------------------------------------------- 00082 Node* Node::getParent(void) const 00083 { 00084 return mParent; 00085 } 00086 00087 //----------------------------------------------------------------------- 00088 void Node::setParent(Node* parent) 00089 { 00090 mParent = parent; 00091 // Request update from parent 00092 mParentNotified = false ; 00093 needUpdate(); 00094 } 00095 00096 //----------------------------------------------------------------------- 00097 Matrix4 Node::_getFullTransform(void) const 00098 { 00099 if (mCachedTransformOutOfDate) 00100 { 00101 // Use derived values 00102 makeTransform( 00103 _getDerivedPosition(), _getDerivedScale(), 00104 _getDerivedOrientation(), mCachedTransform); 00105 mCachedTransformOutOfDate = false; 00106 } 00107 return mCachedTransform; 00108 } 00109 //----------------------------------------------------------------------- 00110 void Node::_update(bool updateChildren, bool parentHasChanged) 00111 { 00112 // always clear information about parent notification 00113 mParentNotified = false ; 00114 00115 // Short circuit the off case 00116 if (!updateChildren && !mNeedParentUpdate && !mNeedChildUpdate && !parentHasChanged ) 00117 { 00118 return; 00119 } 00120 00121 00122 // See if we should process everyone 00123 if (mNeedParentUpdate || parentHasChanged) 00124 { 00125 // Update transforms from parent 00126 _updateFromParent(); 00127 mNeedParentUpdate = false; 00128 } 00129 00130 if (mNeedChildUpdate || parentHasChanged) 00131 { 00132 00133 ChildNodeMap::iterator it, itend; 00134 itend = mChildren.end(); 00135 for (it = mChildren.begin(); it != itend; ++it) 00136 { 00137 Node* child = it->second; 00138 child->_update(true, true); 00139 } 00140 mChildrenToUpdate.clear(); 00141 } 00142 else 00143 { 00144 // Just update selected children 00145 00146 ChildUpdateSet::iterator it, itend; 00147 itend = mChildrenToUpdate.end(); 00148 for(it = mChildrenToUpdate.begin(); it != itend; ++it) 00149 { 00150 Node* child = *it; 00151 child->_update(true, false); 00152 } 00153 00154 mChildrenToUpdate.clear(); 00155 } 00156 00157 mNeedChildUpdate = false; 00158 00159 } 00160 00161 //----------------------------------------------------------------------- 00162 void Node::_updateFromParent(void) const 00163 { 00164 if (mParent) 00165 { 00166 // Combine orientation with that of parent 00167 Quaternion mParentQ = mParent->_getDerivedOrientation(); 00168 mDerivedOrientation = mParentQ * mOrientation; 00169 00170 // Change position vector based on parent's orientation & scale 00171 mDerivedPosition = mParentQ * (mPosition * mParent->_getDerivedScale()); 00172 00173 // Update scale 00174 if (mInheritScale) 00175 { 00176 // Scale own position by parent scale 00177 Vector3 parentScale = mParent->_getDerivedScale(); 00178 // Set own scale, NB just combine as equivalent axes, no shearing 00179 mDerivedScale = mScale * parentScale; 00180 00181 } 00182 else 00183 { 00184 // No inheritence 00185 mDerivedScale = mScale; 00186 } 00187 00188 // Add altered position vector to parents 00189 mDerivedPosition += mParent->_getDerivedPosition(); 00190 } 00191 else 00192 { 00193 // Root node, no parent 00194 mDerivedOrientation = mOrientation; 00195 mDerivedPosition = mPosition; 00196 mDerivedScale = mScale; 00197 } 00198 00199 mCachedTransformOutOfDate = true; 00200 00201 00202 } 00203 //----------------------------------------------------------------------- 00204 Node* Node::createChild(const Vector3& translate, const Quaternion& rotate) 00205 { 00206 Node* newNode = createChildImpl(); 00207 newNode->translate(translate); 00208 newNode->rotate(rotate); 00209 this->addChild(newNode); 00210 00211 return newNode; 00212 } 00213 //----------------------------------------------------------------------- 00214 Node* Node::createChild(const String& name, const Vector3& translate, const Quaternion& rotate) 00215 { 00216 Node* newNode = createChildImpl(name); 00217 newNode->translate(translate); 00218 newNode->rotate(rotate); 00219 this->addChild(newNode); 00220 00221 return newNode; 00222 } 00223 //----------------------------------------------------------------------- 00224 void Node::addChild(Node* child) 00225 { 00226 mChildren.insert(ChildNodeMap::value_type(child->getName(), child)); 00227 child->setParent(this); 00228 00229 } 00230 //----------------------------------------------------------------------- 00231 unsigned short Node::numChildren(void) const 00232 { 00233 return static_cast< unsigned short >( mChildren.size() ); 00234 } 00235 //----------------------------------------------------------------------- 00236 Node* Node::getChild(unsigned short index) const 00237 { 00238 if( index < mChildren.size() ) 00239 { 00240 ChildNodeMap::const_iterator i = mChildren.begin(); 00241 while (index--) ++i; 00242 return i->second; 00243 } 00244 else 00245 return NULL; 00246 } 00247 //----------------------------------------------------------------------- 00248 Node* Node::removeChild(unsigned short index) 00249 { 00250 Node* ret; 00251 if (index < mChildren.size()) 00252 { 00253 ChildNodeMap::iterator i = mChildren.begin(); 00254 while (index--) ++i; 00255 ret = i->second; 00256 // cancel any pending update 00257 cancelUpdate(ret); 00258 00259 mChildren.erase(i); 00260 ret->setParent(NULL); 00261 return ret; 00262 } 00263 else 00264 { 00265 Except( 00266 Exception::ERR_INVALIDPARAMS, 00267 "Child index out of bounds.", 00268 "Node::getChild" ); 00269 } 00270 needUpdate(); 00271 return 0; 00272 } 00273 //----------------------------------------------------------------------- 00274 const Quaternion& Node::getOrientation() const 00275 { 00276 return mOrientation; 00277 } 00278 00279 //----------------------------------------------------------------------- 00280 void Node::setOrientation( const Quaternion & q ) 00281 { 00282 mOrientation = q; 00283 needUpdate(); 00284 } 00285 //----------------------------------------------------------------------- 00286 void Node::setOrientation( Real w, Real x, Real y, Real z) 00287 { 00288 mOrientation.w = w; 00289 mOrientation.x = x; 00290 mOrientation.y = y; 00291 mOrientation.z = z; 00292 needUpdate(); 00293 } 00294 //----------------------------------------------------------------------- 00295 void Node::resetOrientation(void) 00296 { 00297 mOrientation = Quaternion::IDENTITY; 00298 needUpdate(); 00299 } 00300 00301 //----------------------------------------------------------------------- 00302 void Node::setPosition(const Vector3& pos) 00303 { 00304 mPosition = pos; 00305 needUpdate(); 00306 } 00307 00308 00309 //----------------------------------------------------------------------- 00310 void Node::setPosition(Real x, Real y, Real z) 00311 { 00312 Vector3 v(x,y,z); 00313 setPosition(v); 00314 } 00315 00316 //----------------------------------------------------------------------- 00317 const Vector3 & Node::getPosition(void) const 00318 { 00319 return mPosition; 00320 } 00321 //----------------------------------------------------------------------- 00322 Matrix3 Node::getLocalAxes(void) const 00323 { 00324 Vector3 axisX = Vector3::UNIT_X; 00325 Vector3 axisY = Vector3::UNIT_Y; 00326 Vector3 axisZ = Vector3::UNIT_Z; 00327 00328 axisX = mOrientation * axisX; 00329 axisY = mOrientation * axisY; 00330 axisZ = mOrientation * axisZ; 00331 00332 return Matrix3(axisX.x, axisY.x, axisZ.x, 00333 axisX.y, axisY.y, axisZ.y, 00334 axisX.z, axisY.z, axisZ.z); 00335 } 00336 00337 //----------------------------------------------------------------------- 00338 void Node::translate(const Vector3& d) 00339 { 00340 mPosition += d; 00341 needUpdate(); 00342 00343 } 00344 //----------------------------------------------------------------------- 00345 void Node::translate(Real x, Real y, Real z) 00346 { 00347 Vector3 v(x,y,z); 00348 translate(v); 00349 } 00350 //----------------------------------------------------------------------- 00351 void Node::translate(const Matrix3& axes, const Vector3& move) 00352 { 00353 Vector3 derived = axes * move; 00354 translate(derived); 00355 } 00356 //----------------------------------------------------------------------- 00357 void Node::translate(const Matrix3& axes, Real x, Real y, Real z) 00358 { 00359 Vector3 d(x,y,z); 00360 translate(axes,d); 00361 } 00362 //----------------------------------------------------------------------- 00363 void Node::roll(Real angleunits) 00364 { 00365 rotate(Vector3::UNIT_Z, angleunits); 00366 } 00367 //----------------------------------------------------------------------- 00368 void Node::pitch(Real angleunits) 00369 { 00370 rotate(Vector3::UNIT_X, angleunits); 00371 } 00372 //----------------------------------------------------------------------- 00373 void Node::yaw(Real angleunits) 00374 { 00375 rotate(Vector3::UNIT_Y, angleunits); 00376 00377 } 00378 //----------------------------------------------------------------------- 00379 void Node::rotate(const Vector3& axis, Real angleunits) 00380 { 00381 Quaternion q; 00382 q.FromAngleAxis(Math::AngleUnitsToRadians(angleunits),axis); 00383 rotate(q); 00384 } 00385 00386 //----------------------------------------------------------------------- 00387 void Node::rotate(const Quaternion& q) 00388 { 00389 // Note the order of the mult, i.e. q comes after 00390 mOrientation = mOrientation * q; 00391 needUpdate(); 00392 } 00393 //----------------------------------------------------------------------- 00394 const Quaternion & Node::_getDerivedOrientation(void) const 00395 { 00396 if (mNeedParentUpdate) 00397 { 00398 _updateFromParent(); 00399 mNeedParentUpdate = false; 00400 } 00401 return mDerivedOrientation; 00402 } 00403 //----------------------------------------------------------------------- 00404 const Vector3 & Node::_getDerivedPosition(void) const 00405 { 00406 if (mNeedParentUpdate) 00407 { 00408 _updateFromParent(); 00409 mNeedParentUpdate = false; 00410 } 00411 return mDerivedPosition; 00412 } 00413 //----------------------------------------------------------------------- 00414 const Vector3 & Node::_getDerivedScale(void) const 00415 { 00416 return mDerivedScale; 00417 } 00418 //----------------------------------------------------------------------- 00419 void Node::removeAllChildren(void) 00420 { 00421 mChildren.clear(); 00422 } 00423 //----------------------------------------------------------------------- 00424 void Node::setScale(const Vector3& scale) 00425 { 00426 mScale = scale; 00427 needUpdate(); 00428 } 00429 //----------------------------------------------------------------------- 00430 void Node::setScale(Real x, Real y, Real z) 00431 { 00432 mScale.x = x; 00433 mScale.y = y; 00434 mScale.z = z; 00435 needUpdate(); 00436 } 00437 //----------------------------------------------------------------------- 00438 const Vector3 & Node::getScale(void) const 00439 { 00440 return mScale; 00441 } 00442 //----------------------------------------------------------------------- 00443 void Node::setInheritScale(bool inherit) 00444 { 00445 mInheritScale = inherit; 00446 needUpdate(); 00447 } 00448 //----------------------------------------------------------------------- 00449 bool Node::getInheritScale(void) const 00450 { 00451 return mInheritScale; 00452 } 00453 //----------------------------------------------------------------------- 00454 void Node::scale(const Vector3& scale) 00455 { 00456 mScale = mScale * scale; 00457 needUpdate(); 00458 00459 } 00460 //----------------------------------------------------------------------- 00461 void Node::scale(Real x, Real y, Real z) 00462 { 00463 mScale.x *= x; 00464 mScale.y *= y; 00465 mScale.z *= z; 00466 needUpdate(); 00467 00468 } 00469 //----------------------------------------------------------------------- 00470 void Node::makeTransform(const Vector3& position, const Vector3& scale, const Quaternion& orientation, 00471 Matrix4& destMatrix) const 00472 { 00473 destMatrix = Matrix4::IDENTITY; 00474 // Ordering: 00475 // 1. Scale 00476 // 2. Rotate 00477 // 3. Translate 00478 00479 // Parent scaling is already applied to derived position 00480 // Own scale is applied before rotation 00481 Matrix3 rot3x3, scale3x3; 00482 orientation.ToRotationMatrix(rot3x3); 00483 scale3x3 = Matrix3::ZERO; 00484 scale3x3[0][0] = scale.x; 00485 scale3x3[1][1] = scale.y; 00486 scale3x3[2][2] = scale.z; 00487 00488 destMatrix = rot3x3 * scale3x3; 00489 destMatrix.setTrans(position); 00490 } 00491 //----------------------------------------------------------------------- 00492 void Node::makeInverseTransform(const Vector3& position, const Vector3& scale, const Quaternion& orientation, 00493 Matrix4& destMatrix) 00494 { 00495 destMatrix = Matrix4::IDENTITY; 00496 00497 // Invert the parameters 00498 Vector3 invTranslate = -position; 00499 Vector3 invScale; 00500 invScale.x = 1 / scale.x; 00501 invScale.y = 1 / scale.y; 00502 invScale.z = 1 / scale.z; 00503 00504 Quaternion invRot = orientation.Inverse(); 00505 00506 // Because we're inverting, order is translation, rotation, scale 00507 // So make translation relative to scale & rotation 00508 invTranslate.x *= invScale.x; // scale 00509 invTranslate.y *= invScale.y; // scale 00510 invTranslate.z *= invScale.z; // scale 00511 invTranslate = invRot * invTranslate; // rotate 00512 00513 // Next, make a 3x3 rotation matrix and apply inverse scale 00514 Matrix3 rot3x3, scale3x3; 00515 invRot.ToRotationMatrix(rot3x3); 00516 scale3x3 = Matrix3::ZERO; 00517 scale3x3[0][0] = invScale.x; 00518 scale3x3[1][1] = invScale.y; 00519 scale3x3[2][2] = invScale.z; 00520 00521 // Set up final matrix with scale & rotation 00522 destMatrix = scale3x3 * rot3x3; 00523 00524 destMatrix.setTrans(invTranslate); 00525 } 00526 //----------------------------------------------------------------------- 00527 const String& Node::getName(void) const 00528 { 00529 return mName; 00530 } 00531 //----------------------------------------------------------------------- 00532 Material* Node::getMaterial(void) const 00533 { 00534 static Material* pMaterial = 0; 00535 00536 if (!pMaterial) 00537 { 00538 pMaterial = (Material*)MaterialManager::getSingleton().getByName("Core/NodeMaterial"); 00539 if (!pMaterial) 00540 Except( Exception::ERR_ITEM_NOT_FOUND, "Could not find material Core/NodeMaterial", 00541 "Node::getMaterial" ); 00542 pMaterial->load(); 00543 } 00544 return pMaterial; 00545 00546 } 00547 //----------------------------------------------------------------------- 00548 void Node::getRenderOperation(RenderOperation& op) 00549 { 00550 static SubMesh* pSubMesh = 0; 00551 if (!pSubMesh) 00552 { 00553 Mesh *pMesh = MeshManager::getSingleton().load("axes.mesh"); 00554 pSubMesh = pMesh->getSubMesh(0); 00555 } 00556 pSubMesh->_getRenderOperation(op); 00557 } 00558 //----------------------------------------------------------------------- 00559 void Node::getWorldTransforms(Matrix4* xform) const 00560 { 00561 // Assumes up to date 00562 *xform = this->_getFullTransform(); 00563 } 00564 //----------------------------------------------------------------------- 00565 const Quaternion& Node::getWorldOrientation(void) const 00566 { 00567 return _getDerivedOrientation(); 00568 } 00569 //----------------------------------------------------------------------- 00570 const Vector3& Node::getWorldPosition(void) const 00571 { 00572 return _getDerivedPosition(); 00573 } 00574 //----------------------------------------------------------------------- 00575 void Node::setInitialState(void) 00576 { 00577 mInitialPosition = mPosition; 00578 mInitialOrientation = mOrientation; 00579 mInitialScale = mScale; 00580 } 00581 //----------------------------------------------------------------------- 00582 void Node::resetToInitialState(void) 00583 { 00584 mPosition = mInitialPosition; 00585 mOrientation = mInitialOrientation; 00586 mScale = mInitialScale; 00587 00588 // Reset weights 00589 mAccumAnimWeight = 0.0f; 00590 mTransFromInitial = Vector3::ZERO; 00591 mRotFromInitial = Quaternion::IDENTITY; 00592 mScaleFromInitial = Vector3::UNIT_SCALE; 00593 00594 needUpdate(); 00595 } 00596 //----------------------------------------------------------------------- 00597 const Vector3& Node::getInitialPosition(void) const 00598 { 00599 return mInitialPosition; 00600 } 00601 //----------------------------------------------------------------------- 00602 const Quaternion& Node::getInitialOrientation(void) const 00603 { 00604 return mInitialOrientation; 00605 00606 } 00607 //----------------------------------------------------------------------- 00608 const Vector3& Node::getInitialScale(void) const 00609 { 00610 return mInitialScale; 00611 } 00612 //----------------------------------------------------------------------- 00613 Node* Node::getChild(const String& name) const 00614 { 00615 ChildNodeMap::const_iterator i = mChildren.find(name); 00616 00617 if (i == mChildren.end()) 00618 { 00619 Except(Exception::ERR_ITEM_NOT_FOUND, "Child node named " + name + 00620 " does not exist.", "Node::getChild"); 00621 } 00622 return i->second; 00623 00624 } 00625 //----------------------------------------------------------------------- 00626 Node* Node::removeChild(const String& name) 00627 { 00628 ChildNodeMap::iterator i = mChildren.find(name); 00629 00630 if (i == mChildren.end()) 00631 { 00632 Except(Exception::ERR_ITEM_NOT_FOUND, "Child node named " + name + 00633 " does not exist.", "Node::removeChild"); 00634 } 00635 00636 Node* ret = i->second; 00637 // Cancel any pending update 00638 cancelUpdate(ret); 00639 00640 mChildren.erase(i); 00641 ret->setParent(NULL); 00642 00643 return ret; 00644 00645 00646 } 00647 //----------------------------------------------------------------------- 00648 Node::ChildNodeIterator Node::getChildIterator(void) 00649 { 00650 return ChildNodeIterator(mChildren.begin(), mChildren.end()); 00651 } 00652 //----------------------------------------------------------------------- 00653 void Node::_weightedTransform(Real weight, const Vector3& translate, 00654 const Quaternion& rotate, const Vector3& scale) 00655 { 00656 // If no previous transforms, we can just apply 00657 if (mAccumAnimWeight == 0.0f) 00658 { 00659 mRotFromInitial = rotate; 00660 mTransFromInitial = translate; 00661 mScaleFromInitial = scale; 00662 mAccumAnimWeight = weight; 00663 } 00664 else 00665 { 00666 // Blend with existing 00667 Real factor = weight / (mAccumAnimWeight + weight); 00668 mTransFromInitial += (translate - mTransFromInitial) * factor; 00669 mRotFromInitial = 00670 Quaternion::Slerp(factor, mRotFromInitial, rotate); 00671 // For scale, find delta from 1.0, factor then add back before applying 00672 Vector3 scaleDiff = (scale - Vector3::UNIT_SCALE) * factor; 00673 mScaleFromInitial = mScaleFromInitial * 00674 (scaleDiff + Vector3::UNIT_SCALE); 00675 mAccumAnimWeight += weight; 00676 00677 } 00678 00679 // Update final based on bind position + offsets 00680 mOrientation = mInitialOrientation * mRotFromInitial; 00681 mPosition = mInitialPosition + mTransFromInitial; 00682 mScale = mInitialScale * mScaleFromInitial; 00683 needUpdate(); 00684 00685 } 00686 //----------------------------------------------------------------------- 00687 Real Node::getSquaredViewDepth(const Camera* cam) const 00688 { 00689 Vector3 diff = _getDerivedPosition() - cam->getDerivedPosition(); 00690 00691 // NB use squared length rather than real depth to avoid square root 00692 return diff.squaredLength(); 00693 } 00694 //----------------------------------------------------------------------- 00695 void Node::needUpdate() 00696 { 00697 // If we're already going to update everything this doesn't matter 00698 /* FIX: removed because this causes newly created nodes 00699 which already have mNeedUpdate == true not to notify parent when 00700 added! 00701 if (mNeedUpdate) 00702 { 00703 return; 00704 } 00705 */ 00706 00707 mNeedParentUpdate = true; 00708 mNeedChildUpdate = true; 00709 mCachedTransformOutOfDate = true; 00710 00711 // Make sure we're not root and parent hasn't been notified before 00712 if (mParent && !mParentNotified) 00713 { 00714 mParent->requestUpdate(this); 00715 mParentNotified = true ; 00716 } 00717 00718 // all children will be updated 00719 mChildrenToUpdate.clear(); 00720 } 00721 //----------------------------------------------------------------------- 00722 void Node::requestUpdate(Node* child) 00723 { 00724 // If we're already going to update everything this doesn't matter 00725 if (mNeedChildUpdate) 00726 { 00727 return; 00728 } 00729 00730 mChildrenToUpdate.insert(child); 00731 // Request selective update of me, if we didn't do it before 00732 if (mParent && !mParentNotified) { 00733 mParent->requestUpdate(this); 00734 mParentNotified = true ; 00735 } 00736 00737 } 00738 //----------------------------------------------------------------------- 00739 void Node::cancelUpdate(Node* child) 00740 { 00741 mChildrenToUpdate.erase(child); 00742 00743 // Propogate this up if we're done 00744 if (mChildrenToUpdate.empty() && mParent && !mNeedChildUpdate) 00745 { 00746 mParent->cancelUpdate(this); 00747 mParentNotified = false ; 00748 } 00749 } 00750 } 00751
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:19 2004