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 "OgreSceneNode.h" 00027 00028 #include "OgreException.h" 00029 #include "OgreEntity.h" 00030 #include "OgreCamera.h" 00031 #include "OgreLight.h" 00032 #include "OgreMath.h" 00033 #include "OgreSceneManager.h" 00034 #include "OgreMovableObject.h" 00035 #include "OgreWireBoundingBox.h" 00036 00037 namespace Ogre { 00038 //----------------------------------------------------------------------- 00039 SceneNode::SceneNode(SceneManager* creator) 00040 : Node(), mLightListDirty(true), mWireBoundingBox(0), mShowBoundingBox(false), 00041 mCreator(creator), mYawFixed(false), mAutoTrackTarget(0) 00042 { 00043 needUpdate(); 00044 } 00045 //----------------------------------------------------------------------- 00046 SceneNode::SceneNode(SceneManager* creator, const String& name) 00047 : Node(name), mLightListDirty(true), mWireBoundingBox(0), mShowBoundingBox(false), 00048 mCreator(creator), mYawFixed(false), mAutoTrackTarget(0) 00049 { 00050 needUpdate(); 00051 } 00052 //----------------------------------------------------------------------- 00053 SceneNode::~SceneNode() 00054 { 00055 // Detach all objects, do this manually to avoid needUpdate() call 00056 // which can fail because of deleted items 00057 ObjectMap::iterator itr; 00058 MovableObject* ret; 00059 for ( itr = mObjectsByName.begin(); itr != mObjectsByName.end(); itr++ ) 00060 { 00061 ret = itr->second; 00062 ret->_notifyAttached((SceneNode*)0); 00063 } 00064 mObjectsByName.clear(); 00065 00066 if (mWireBoundingBox) { 00067 delete mWireBoundingBox; 00068 } 00069 } 00070 //----------------------------------------------------------------------- 00071 void SceneNode::_update(bool updateChildren, bool parentHasChanged) 00072 { 00073 Node::_update(updateChildren, parentHasChanged); 00074 _updateBounds(); 00075 mLightListDirty = true; 00076 00077 } 00078 00079 //----------------------------------------------------------------------- 00080 void SceneNode::attachObject(MovableObject* obj) 00081 { 00082 obj->_notifyAttached(this); 00083 00084 // Also add to name index 00085 std::pair<ObjectMap::iterator, bool> insresult = 00086 mObjectsByName.insert(ObjectMap::value_type(obj->getName(), obj)); 00087 assert(insresult.second && "Object was not attached because an object of the " 00088 "same name was already attached to this node."); 00089 00090 // Make sure bounds get updated (must go right to the top) 00091 needUpdate(); 00092 } 00093 //----------------------------------------------------------------------- 00094 unsigned short SceneNode::numAttachedObjects(void) const 00095 { 00096 return static_cast< unsigned short >( mObjectsByName.size() ); 00097 } 00098 //----------------------------------------------------------------------- 00099 MovableObject* SceneNode::getAttachedObject(unsigned short index) 00100 { 00101 if (index < mObjectsByName.size()) 00102 { 00103 ObjectMap::iterator i = mObjectsByName.begin(); 00104 // Increment (must do this one at a time) 00105 while (index--)++i; 00106 00107 return i->second; 00108 } 00109 else 00110 { 00111 Except(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttachedObject"); 00112 } 00113 return 0; 00114 } 00115 //----------------------------------------------------------------------- 00116 MovableObject* SceneNode::getAttachedObject(const String& name) 00117 { 00118 // Look up 00119 ObjectMap::iterator i = mObjectsByName.find(name); 00120 00121 if (i == mObjectsByName.end()) 00122 { 00123 Except(Exception::ERR_ITEM_NOT_FOUND, "Attached object " + 00124 name + " not found.", "SceneNode::getAttachedObject"); 00125 } 00126 00127 return i->second; 00128 00129 } 00130 //----------------------------------------------------------------------- 00131 MovableObject* SceneNode::detachObject(unsigned short index) 00132 { 00133 MovableObject* ret; 00134 if (index < mObjectsByName.size()) 00135 { 00136 00137 ObjectMap::iterator i = mObjectsByName.begin(); 00138 // Increment (must do this one at a time) 00139 while (index--)++i; 00140 00141 ret = i->second; 00142 mObjectsByName.erase(i); 00143 ret->_notifyAttached((SceneNode*)0); 00144 00145 // Make sure bounds get updated (must go right to the top) 00146 needUpdate(); 00147 00148 return ret; 00149 00150 } 00151 else 00152 { 00153 Except(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttchedEntity"); 00154 } 00155 return 0; 00156 00157 } 00158 //----------------------------------------------------------------------- 00159 MovableObject* SceneNode::detachObject(const String& name) 00160 { 00161 ObjectMap::iterator it = mObjectsByName.find(name); 00162 if (it == mObjectsByName.end()) 00163 { 00164 Except(Exception::ERR_ITEM_NOT_FOUND, "Object " + name + " is not attached " 00165 "to this node.", "SceneNode::detachObject"); 00166 } 00167 MovableObject* ret = it->second; 00168 mObjectsByName.erase(it); 00169 ret->_notifyAttached((SceneNode*)0); 00170 // Make sure bounds get updated (must go right to the top) 00171 needUpdate(); 00172 00173 return ret; 00174 00175 } 00176 //----------------------------------------------------------------------- 00177 void SceneNode::detachObject(MovableObject* obj) 00178 { 00179 ObjectMap::iterator i, iend; 00180 iend = mObjectsByName.end(); 00181 for (i = mObjectsByName.begin(); i != iend; ++i) 00182 { 00183 if (i->second == obj) 00184 { 00185 mObjectsByName.erase(i); 00186 break; 00187 } 00188 } 00189 obj->_notifyAttached((SceneNode*)0); 00190 00191 // Make sure bounds get updated (must go right to the top) 00192 needUpdate(); 00193 00194 } 00195 //----------------------------------------------------------------------- 00196 void SceneNode::attachCamera(Camera* cam) 00197 { 00198 attachObject(cam); 00199 } 00200 //----------------------------------------------------------------------- 00201 void SceneNode::attachLight(Light* lgt) 00202 { 00203 attachObject(lgt); 00204 } 00205 //----------------------------------------------------------------------- 00206 void SceneNode::detachAllObjects(void) 00207 { 00208 ObjectMap::iterator itr; 00209 MovableObject* ret; 00210 for ( itr = mObjectsByName.begin(); itr != mObjectsByName.end(); itr++ ) 00211 { 00212 ret = itr->second; 00213 ret->_notifyAttached((SceneNode*)0); 00214 } 00215 mObjectsByName.clear(); 00216 // Make sure bounds get updated (must go right to the top) 00217 needUpdate(); 00218 } 00219 //----------------------------------------------------------------------- 00220 void SceneNode::_updateBounds(void) 00221 { 00222 // Reset bounds first 00223 mWorldAABB.setNull(); 00224 00225 // Update bounds from own attached objects 00226 ObjectMap::iterator i; 00227 AxisAlignedBox bx; 00228 for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i) 00229 { 00230 // Merge world bounds of each object 00231 mWorldAABB.merge(i->second->getWorldBoundingBox(true)); 00232 } 00233 00234 // Merge with children 00235 ChildNodeMap::iterator child; 00236 for (child = mChildren.begin(); child != mChildren.end(); ++child) 00237 { 00238 SceneNode* sceneChild = static_cast<SceneNode*>(child->second); 00239 mWorldAABB.merge(sceneChild->mWorldAABB); 00240 } 00241 00242 } 00243 //----------------------------------------------------------------------- 00244 void SceneNode::_findVisibleObjects(Camera* cam, RenderQueue* queue, 00245 bool includeChildren, bool displayNodes, bool onlyShadowCasters) 00246 { 00247 // Check self visible 00248 if (!cam->isVisible(mWorldAABB)) 00249 return; 00250 00251 // Add all entities 00252 ObjectMap::iterator iobj; 00253 ObjectMap::iterator iobjend = mObjectsByName.end(); 00254 for (iobj = mObjectsByName.begin(); iobj != iobjend; ++iobj) 00255 { 00256 // Tell attached objects about camera position (incase any extra processing they want to do) 00257 iobj->second->_notifyCurrentCamera(cam); 00258 if (iobj->second->isVisible() && 00259 (!onlyShadowCasters || iobj->second->getCastShadows())) 00260 { 00261 iobj->second->_updateRenderQueue(queue); 00262 } 00263 } 00264 00265 if (includeChildren) 00266 { 00267 ChildNodeMap::iterator child, childend; 00268 childend = mChildren.end(); 00269 for (child = mChildren.begin(); child != childend; ++child) 00270 { 00271 SceneNode* sceneChild = static_cast<SceneNode*>(child->second); 00272 sceneChild->_findVisibleObjects(cam, queue, includeChildren, displayNodes); 00273 } 00274 } 00275 00276 if (displayNodes) 00277 { 00278 // Include self in the render queue 00279 queue->addRenderable(this); 00280 } 00281 00282 // Check if the bounding box should be shown. 00283 // See if our flag is set or if the scene manager flag is set. 00284 if (mShowBoundingBox || (mCreator && mCreator->getShowBoundingBoxes())) 00285 { 00286 _addBoundingBoxToQueue(queue); 00287 } 00288 00289 00290 } 00291 00292 00293 void SceneNode::_addBoundingBoxToQueue(RenderQueue* queue) { 00294 // Create a WireBoundingBox if needed. 00295 if (mWireBoundingBox == NULL) { 00296 mWireBoundingBox = new WireBoundingBox(); 00297 } 00298 mWireBoundingBox->setupBoundingBox(mWorldAABB); 00299 queue->addRenderable(mWireBoundingBox); 00300 } 00301 00302 void SceneNode::showBoundingBox(bool bShow) { 00303 mShowBoundingBox = bShow; 00304 } 00305 00306 bool SceneNode::getShowBoundingBox() const { 00307 return mShowBoundingBox; 00308 } 00309 00310 00311 //----------------------------------------------------------------------- 00312 Node* SceneNode::createChildImpl(void) 00313 { 00314 // Support detached scene nodes 00315 if (mCreator) 00316 { 00317 return mCreator->createSceneNode(); 00318 } 00319 else 00320 { 00321 return new SceneNode(NULL); 00322 } 00323 } 00324 //----------------------------------------------------------------------- 00325 Node* SceneNode::createChildImpl(const String& name) 00326 { 00327 // Support detached scene nodes 00328 if (mCreator) 00329 { 00330 return mCreator->createSceneNode(name); 00331 } 00332 else 00333 { 00334 return new SceneNode(NULL, name); 00335 } 00336 } 00337 //----------------------------------------------------------------------- 00338 AxisAlignedBox SceneNode::_getWorldAABB(void) const 00339 { 00340 return mWorldAABB; 00341 } 00342 //----------------------------------------------------------------------- 00343 SceneNode::ObjectIterator SceneNode::getAttachedObjectIterator(void) 00344 { 00345 return ObjectIterator(mObjectsByName.begin(), mObjectsByName.end()); 00346 } 00347 //----------------------------------------------------------------------- 00348 SceneManager* SceneNode::getCreator(void) const 00349 { 00350 return mCreator; 00351 } 00352 //----------------------------------------------------------------------- 00353 void SceneNode::removeAndDestroyChild(const String& name) 00354 { 00355 SceneNode* pChild = static_cast<SceneNode*>(getChild(name)); 00356 pChild->removeAndDestroyAllChildren(); 00357 00358 removeChild(name); 00359 pChild->getCreator()->destroySceneNode(name); 00360 00361 } 00362 //----------------------------------------------------------------------- 00363 void SceneNode::removeAndDestroyChild(unsigned short index) 00364 { 00365 SceneNode* pChild = static_cast<SceneNode*>(getChild(index)); 00366 pChild->removeAndDestroyAllChildren(); 00367 00368 removeChild(index); 00369 pChild->getCreator()->destroySceneNode(pChild->getName()); 00370 } 00371 //----------------------------------------------------------------------- 00372 void SceneNode::removeAndDestroyAllChildren(void) 00373 { 00374 ChildNodeMap::iterator i, iend; 00375 iend = mChildren.end(); 00376 for (i = mChildren.begin(); i != iend; ++i) 00377 { 00378 SceneNode* sn = static_cast<SceneNode*>(i->second); 00379 sn->removeAndDestroyAllChildren(); 00380 sn->getCreator()->destroySceneNode(sn->getName()); 00381 } 00382 mChildren.clear(); 00383 needUpdate(); 00384 } 00385 //----------------------------------------------------------------------- 00386 SceneNode* SceneNode::createChildSceneNode(const Vector3& translate, 00387 const Quaternion& rotate) 00388 { 00389 return static_cast<SceneNode*>(this->createChild(translate, rotate)); 00390 } 00391 //----------------------------------------------------------------------- 00392 SceneNode* SceneNode::createChildSceneNode(const String& name, const Vector3& translate, 00393 const Quaternion& rotate) 00394 { 00395 return static_cast<SceneNode*>(this->createChild(name, translate, rotate)); 00396 } 00397 //----------------------------------------------------------------------- 00398 const LightList& SceneNode::getLights(void) const 00399 { 00400 // TEMP FIX 00401 // If a scene node is static and lights have moved, light list won't change 00402 // can't use a simple global boolean flag since this is only called for 00403 // visible nodes, so temporarily visible nodes will not be updated 00404 // Since this is only called for visible nodes, skip the check for now 00405 //if (mLightListDirty) 00406 if (mCreator) 00407 { 00408 // Use SceneManager to calculate 00409 mCreator->_populateLightList(this->_getDerivedPosition(), mLightList); 00410 mLightListDirty = false; 00411 } 00412 return mLightList; 00413 00414 } 00415 //----------------------------------------------------------------------- 00416 void SceneNode::setAutoTracking(bool enabled, SceneNode* target, 00417 const Vector3& localDirectionVector, 00418 const Vector3& offset) 00419 { 00420 if (enabled) 00421 { 00422 mAutoTrackTarget = target; 00423 mAutoTrackOffset = offset; 00424 mAutoTrackLocalDirection = localDirectionVector; 00425 } 00426 else 00427 { 00428 mAutoTrackTarget = 0; 00429 } 00430 if (mCreator) 00431 mCreator->_notifyAutotrackingSceneNode(this, enabled); 00432 } 00433 //----------------------------------------------------------------------- 00434 void SceneNode::setFixedYawAxis(bool useFixed, const Vector3& fixedAxis) 00435 { 00436 mYawFixed = useFixed; 00437 mYawFixedAxis = fixedAxis; 00438 } 00439 00440 //----------------------------------------------------------------------- 00441 void SceneNode::setDirection(Real x, Real y, Real z, TransformSpace relativeTo, 00442 const Vector3& localDirectionVector) 00443 { 00444 setDirection(Vector3(x,y,z), relativeTo, localDirectionVector); 00445 } 00446 00447 //----------------------------------------------------------------------- 00448 void SceneNode::setDirection(const Vector3& vec, TransformSpace relativeTo, 00449 const Vector3& localDirectionVector) 00450 { 00451 // Do nothing if given a zero vector 00452 if (vec == Vector3::ZERO) return; 00453 00454 // Adjust vector so that it is relative to local Z 00455 Vector3 zAdjustVec; 00456 if (localDirectionVector == Vector3::NEGATIVE_UNIT_Z) 00457 { 00458 zAdjustVec = -vec; 00459 } 00460 else 00461 { 00462 Quaternion localToUnitZ = localDirectionVector.getRotationTo(Vector3::UNIT_Z); 00463 zAdjustVec = localToUnitZ * vec; 00464 } 00465 zAdjustVec.normalise(); 00466 00467 Quaternion targetOrientation; 00468 if( mYawFixed ) 00469 { 00470 Vector3 xVec = mYawFixedAxis.crossProduct( zAdjustVec ); 00471 xVec.normalise(); 00472 00473 Vector3 yVec = zAdjustVec.crossProduct( xVec ); 00474 yVec.normalise(); 00475 00476 targetOrientation.FromAxes( xVec, yVec, zAdjustVec ); 00477 } 00478 else 00479 { 00480 00481 // Get axes from current quaternion 00482 Vector3 axes[3]; 00483 _getDerivedOrientation().ToAxes(axes); 00484 Quaternion rotQuat; 00485 if (-zAdjustVec == axes[2]) 00486 { 00487 // Oops, a 180 degree turn (infinite possible rotation axes) 00488 // Default to yaw i.e. use current UP 00489 rotQuat.FromAngleAxis(Math::PI, axes[1]); 00490 } 00491 else 00492 { 00493 // Derive shortest arc to new direction 00494 rotQuat = axes[2].getRotationTo(zAdjustVec); 00495 00496 } 00497 targetOrientation = rotQuat * mOrientation; 00498 } 00499 00500 if (relativeTo == TS_LOCAL || !mParent) 00501 { 00502 mOrientation = targetOrientation; 00503 } 00504 else 00505 { 00506 if (relativeTo == TS_PARENT) 00507 { 00508 mOrientation = targetOrientation * mParent->getOrientation().Inverse(); 00509 } 00510 else if (relativeTo == TS_WORLD) 00511 { 00512 mOrientation = targetOrientation * mParent->_getDerivedOrientation().Inverse(); 00513 } 00514 } 00515 00516 00517 } 00518 //----------------------------------------------------------------------- 00519 void SceneNode::lookAt( const Vector3& targetPoint, TransformSpace relativeTo, 00520 const Vector3& localDirectionVector) 00521 { 00522 this->setDirection(targetPoint - _getDerivedPosition(), relativeTo, 00523 localDirectionVector); 00524 } 00525 //----------------------------------------------------------------------- 00526 void SceneNode::_autoTrack(void) 00527 { 00528 // NB assumes that all scene nodes have been updated 00529 if (mAutoTrackTarget) 00530 { 00531 lookAt(mAutoTrackTarget->_getDerivedPosition() + mAutoTrackOffset, 00532 TS_WORLD, mAutoTrackLocalDirection); 00533 // update self & children 00534 _update(true, true); 00535 } 00536 } 00537 00538 00539 }
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:44 2004