source: OGRE/trunk/ogrenew/OgreMain/src/OgreSceneNode.cpp @ 657

Revision 657, 23.2 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

RevLine 
[657]1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreSceneNode.h"
27
28#include "OgreException.h"
29#include "OgreEntity.h"
30#include "OgreCamera.h"
31#include "OgreLight.h"
32#include "OgreMath.h"
33#include "OgreSceneManager.h"
34#include "OgreMovableObject.h"
35#include "OgreWireBoundingBox.h"
36
37namespace Ogre {
38    //-----------------------------------------------------------------------
39    SceneNode::SceneNode(SceneManager* creator)
40    : Node(), mLightListDirty(true), mWireBoundingBox(0),
41        mShowBoundingBox(false), mCreator(creator),
42        mYawFixed(false), mAutoTrackTarget(0), mIsInSceneGraph(false)
43#ifdef GTP_VISIBILITY_MODIFIED_OGRE
44        , mLastVisited(0), mVisible(false), mLastRendered(-1)
45#endif //GTP_VISIBILITY_MODIFIED_OGRE
46    {
47        needUpdate();
48    }
49    //-----------------------------------------------------------------------
50    SceneNode::SceneNode(SceneManager* creator, const String& name)
51    : Node(name), mLightListDirty(true), mWireBoundingBox(0),
52        mShowBoundingBox(false), mCreator(creator), mYawFixed(false),
53        mAutoTrackTarget(0), mIsInSceneGraph(false)
54        #ifdef GTP_VISIBILITY_MODIFIED_OGRE
55        , mLastVisited(0), mVisible(false)
56        #endif //GTP_VISIBILITY_MODIFIED_OGRE
57    {
58        needUpdate();
59    }
60    //-----------------------------------------------------------------------
61    SceneNode::~SceneNode()
62    {
63        // Detach all objects, do this manually to avoid needUpdate() call
64        // which can fail because of deleted items
65                ObjectMap::iterator itr;
66                MovableObject* ret;
67                for ( itr = mObjectsByName.begin(); itr != mObjectsByName.end(); itr++ )
68                {
69                  ret = itr->second;
70                  ret->_notifyAttached((SceneNode*)0);
71                }
72        mObjectsByName.clear();
73
74        if (mWireBoundingBox) {
75                        delete mWireBoundingBox;
76                }
77    }
78    //-----------------------------------------------------------------------
79    void SceneNode::_update(bool updateChildren, bool parentHasChanged)
80    {
81        Node::_update(updateChildren, parentHasChanged);
82        _updateBounds();
83        mLightListDirty = true;
84
85    }
86    //-----------------------------------------------------------------------
87        void SceneNode::setParent(Node* parent)
88        {
89                Node::setParent(parent);
90
91                if (parent)
92                {
93                        SceneNode* sceneParent = static_cast<SceneNode*>(parent);
94                        setInSceneGraph(sceneParent->isInSceneGraph());
95                }
96                else
97                {
98                        setInSceneGraph(false);
99                }
100        }
101    //-----------------------------------------------------------------------
102        void SceneNode::setInSceneGraph(bool inGraph)
103        {
104                if (inGraph != mIsInSceneGraph)
105                {
106                        mIsInSceneGraph = inGraph;
107                        // Tell children
108                ChildNodeMap::iterator child;
109            for (child = mChildren.begin(); child != mChildren.end(); ++child)
110                {
111                SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
112                                sceneChild->setInSceneGraph(inGraph);
113                        }
114                }
115        }
116    //-----------------------------------------------------------------------
117    void SceneNode::attachObject(MovableObject* obj)
118    {
119        obj->_notifyAttached(this);
120
121        // Also add to name index
122        std::pair<ObjectMap::iterator, bool> insresult =
123            mObjectsByName.insert(ObjectMap::value_type(obj->getName(), obj));
124        assert(insresult.second && "Object was not attached because an object of the "
125            "same name was already attached to this node.");
126
127        // Make sure bounds get updated (must go right to the top)
128        needUpdate();
129    }
130    //-----------------------------------------------------------------------
131    unsigned short SceneNode::numAttachedObjects(void) const
132    {
133        return static_cast< unsigned short >( mObjectsByName.size() );
134    }
135    //-----------------------------------------------------------------------
136    MovableObject* SceneNode::getAttachedObject(unsigned short index)
137    {
138        if (index < mObjectsByName.size())
139        {
140            ObjectMap::iterator i = mObjectsByName.begin();
141            // Increment (must do this one at a time)           
142            while (index--)++i;
143
144            return i->second;
145        }
146        else
147        {
148            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttachedObject");
149        }
150        return 0;
151    }
152    //-----------------------------------------------------------------------
153    MovableObject* SceneNode::getAttachedObject(const String& name)
154    {
155        // Look up
156        ObjectMap::iterator i = mObjectsByName.find(name);
157
158        if (i == mObjectsByName.end())
159        {
160            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Attached object " +
161                name + " not found.", "SceneNode::getAttachedObject");
162        }
163
164        return i->second;
165
166    }
167    //-----------------------------------------------------------------------
168    MovableObject* SceneNode::detachObject(unsigned short index)
169    {
170        MovableObject* ret;
171        if (index < mObjectsByName.size())
172        {
173
174            ObjectMap::iterator i = mObjectsByName.begin();
175            // Increment (must do this one at a time)           
176            while (index--)++i;
177
178            ret = i->second;
179            mObjectsByName.erase(i);
180            ret->_notifyAttached((SceneNode*)0);
181
182            // Make sure bounds get updated (must go right to the top)
183            needUpdate();
184
185            return ret;
186
187        }
188        else
189        {
190            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttchedEntity");
191        }
192        return 0;
193
194    }
195    //-----------------------------------------------------------------------
196    MovableObject* SceneNode::detachObject(const String& name)
197    {
198        ObjectMap::iterator it = mObjectsByName.find(name);
199        if (it == mObjectsByName.end())
200        {
201            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Object " + name + " is not attached "
202                "to this node.", "SceneNode::detachObject");
203        }
204        MovableObject* ret = it->second;
205        mObjectsByName.erase(it);
206        ret->_notifyAttached((SceneNode*)0);
207        // Make sure bounds get updated (must go right to the top)
208        needUpdate();
209       
210        return ret;
211
212    }
213    //-----------------------------------------------------------------------
214    void SceneNode::detachObject(MovableObject* obj)
215    {
216        ObjectMap::iterator i, iend;
217        iend = mObjectsByName.end();
218        for (i = mObjectsByName.begin(); i != iend; ++i)
219        {
220            if (i->second == obj)
221            {
222                mObjectsByName.erase(i);
223                break;
224            }
225        }
226        obj->_notifyAttached((SceneNode*)0);
227
228        // Make sure bounds get updated (must go right to the top)
229        needUpdate();
230
231    }
232    //-----------------------------------------------------------------------
233    void SceneNode::detachAllObjects(void)
234    {
235                ObjectMap::iterator itr;
236                MovableObject* ret;
237                for ( itr = mObjectsByName.begin(); itr != mObjectsByName.end(); itr++ )
238                {
239                  ret = itr->second;
240                  ret->_notifyAttached((SceneNode*)0);
241                }
242        mObjectsByName.clear();
243        // Make sure bounds get updated (must go right to the top)
244        needUpdate();
245    }
246    //-----------------------------------------------------------------------
247    void SceneNode::_updateBounds(void)
248    {
249        // Reset bounds first
250        mWorldAABB.setNull();
251
252        // Update bounds from own attached objects
253        ObjectMap::iterator i;
254        for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
255        {
256            // Merge world bounds of each object
257            mWorldAABB.merge(i->second->getWorldBoundingBox(true));
258        }
259
260        // Merge with children
261        ChildNodeMap::iterator child;
262        for (child = mChildren.begin(); child != mChildren.end(); ++child)
263        {
264            SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
265            mWorldAABB.merge(sceneChild->mWorldAABB);
266        }
267
268    }
269    //-----------------------------------------------------------------------
270    void SceneNode::_findVisibleObjects(Camera* cam, RenderQueue* queue,
271        bool includeChildren, bool displayNodes, bool onlyShadowCasters)
272    {
273        // Check self visible
274        if (!cam->isVisible(mWorldAABB))
275            return;
276
277        // Add all entities
278        ObjectMap::iterator iobj;
279        ObjectMap::iterator iobjend = mObjectsByName.end();
280        for (iobj = mObjectsByName.begin(); iobj != iobjend; ++iobj)
281        {
282            // Tell attached objects about camera position (incase any extra processing they want to do)
283            iobj->second->_notifyCurrentCamera(cam);
284            if (iobj->second->isVisible() &&
285                (!onlyShadowCasters || iobj->second->getCastShadows()))
286            {
287                iobj->second->_updateRenderQueue(queue);
288            }
289        }
290
291        if (includeChildren)
292        {
293            ChildNodeMap::iterator child, childend;
294            childend = mChildren.end();
295            for (child = mChildren.begin(); child != childend; ++child)
296            {
297                SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
298                sceneChild->_findVisibleObjects(cam, queue, includeChildren,
299                                        displayNodes, onlyShadowCasters);
300            }
301        }
302
303        if (displayNodes)
304        {
305            // Include self in the render queue
306            queue->addRenderable(this);
307        }
308
309                // Check if the bounding box should be shown.
310                // See if our flag is set or if the scene manager flag is set.
311                if (mShowBoundingBox || (mCreator && mCreator->getShowBoundingBoxes()))
312                {
313                        _addBoundingBoxToQueue(queue);
314                }
315
316
317    }
318
319
320        void SceneNode::_addBoundingBoxToQueue(RenderQueue* queue) {
321                // Create a WireBoundingBox if needed.
322                if (mWireBoundingBox == NULL) {
323                        mWireBoundingBox = new WireBoundingBox();
324                }
325                mWireBoundingBox->setupBoundingBox(mWorldAABB);
326                queue->addRenderable(mWireBoundingBox);
327        }
328
329        void SceneNode::showBoundingBox(bool bShow) {
330                mShowBoundingBox = bShow;
331        }
332
333        bool SceneNode::getShowBoundingBox() const {
334                return mShowBoundingBox;
335        }
336
337
338    //-----------------------------------------------------------------------
339    Node* SceneNode::createChildImpl(void)
340    {
341        assert(mCreator);
342        return mCreator->createSceneNode();
343    }
344    //-----------------------------------------------------------------------
345    Node* SceneNode::createChildImpl(const String& name)
346    {
347        assert(mCreator);
348        return mCreator->createSceneNode(name);
349    }
350    //-----------------------------------------------------------------------
351    AxisAlignedBox SceneNode::_getWorldAABB(void) const
352    {
353        return mWorldAABB;
354    }
355    //-----------------------------------------------------------------------
356    SceneNode::ObjectIterator SceneNode::getAttachedObjectIterator(void)
357    {
358        return ObjectIterator(mObjectsByName.begin(), mObjectsByName.end());
359    }
360        //-----------------------------------------------------------------------
361        SceneNode::ConstObjectIterator SceneNode::getAttachedObjectIterator(void) const
362        {
363                return ConstObjectIterator(mObjectsByName.begin(), mObjectsByName.end());
364        }
365    //-----------------------------------------------------------------------
366    SceneManager* SceneNode::getCreator(void) const
367    {
368        return mCreator;
369    }
370    //-----------------------------------------------------------------------
371    void SceneNode::removeAndDestroyChild(const String& name)
372    {
373        SceneNode* pChild = static_cast<SceneNode*>(getChild(name));
374        pChild->removeAndDestroyAllChildren();
375
376        removeChild(name);
377        pChild->getCreator()->destroySceneNode(name);
378
379    }
380    //-----------------------------------------------------------------------
381    void SceneNode::removeAndDestroyChild(unsigned short index)
382    {
383        SceneNode* pChild = static_cast<SceneNode*>(getChild(index));
384        pChild->removeAndDestroyAllChildren();
385
386        removeChild(index);
387        pChild->getCreator()->destroySceneNode(pChild->getName());
388    }
389    //-----------------------------------------------------------------------
390    void SceneNode::removeAndDestroyAllChildren(void)
391    {
392        ChildNodeMap::iterator i, iend;
393        iend = mChildren.end();
394        for (i = mChildren.begin(); i != iend;)
395        {
396            SceneNode* sn = static_cast<SceneNode*>(i->second);
397                        // increment iterator before destroying (iterator invalidated by
398                        // SceneManager::destroySceneNode because it causes removal from parent)
399                        ++i;
400            sn->removeAndDestroyAllChildren();
401            sn->getCreator()->destroySceneNode(sn->getName());
402        }
403            mChildren.clear();
404        needUpdate();
405    }
406    //-----------------------------------------------------------------------
407        SceneNode* SceneNode::createChildSceneNode(const Vector3& translate,
408        const Quaternion& rotate)
409        {
410                return static_cast<SceneNode*>(this->createChild(translate, rotate));
411        }
412    //-----------------------------------------------------------------------
413    SceneNode* SceneNode::createChildSceneNode(const String& name, const Vector3& translate,
414                const Quaternion& rotate)
415        {
416                return static_cast<SceneNode*>(this->createChild(name, translate, rotate));
417        }
418    //-----------------------------------------------------------------------
419    const LightList& SceneNode::findLights(Real radius) const
420    {
421        // TEMP FIX
422        // If a scene node is static and lights have moved, light list won't change
423        // can't use a simple global boolean flag since this is only called for
424        // visible nodes, so temporarily visible nodes will not be updated
425        // Since this is only called for visible nodes, skip the check for now
426        //if (mLightListDirty)
427        if (mCreator)
428        {
429            // Use SceneManager to calculate
430            mCreator->_populateLightList(this->_getDerivedPosition(), radius, mLightList);
431            mLightListDirty = false;
432        }
433        return mLightList;
434
435    }
436    //-----------------------------------------------------------------------
437    void SceneNode::setAutoTracking(bool enabled, SceneNode* target,
438        const Vector3& localDirectionVector,
439        const Vector3& offset)
440    {
441        if (enabled)
442        {
443            mAutoTrackTarget = target;
444            mAutoTrackOffset = offset;
445            mAutoTrackLocalDirection = localDirectionVector;
446        }
447        else
448        {
449            mAutoTrackTarget = 0;
450        }
451        if (mCreator)
452            mCreator->_notifyAutotrackingSceneNode(this, enabled);
453    }
454    //-----------------------------------------------------------------------
455    void SceneNode::setFixedYawAxis(bool useFixed, const Vector3& fixedAxis)
456    {
457        mYawFixed = useFixed;
458        mYawFixedAxis = fixedAxis;
459    }
460
461        //-----------------------------------------------------------------------
462        void SceneNode::yaw(const Radian& angle, TransformSpace relativeTo)
463        {
464                if (mYawFixed)
465                {
466                        rotate(mYawFixedAxis, angle, relativeTo);
467                }
468                else
469                {
470                        rotate(Vector3::UNIT_Y, angle, relativeTo);
471                }
472
473        }
474    //-----------------------------------------------------------------------
475    void SceneNode::setDirection(Real x, Real y, Real z, TransformSpace relativeTo,
476        const Vector3& localDirectionVector)
477    {
478        setDirection(Vector3(x,y,z), relativeTo, localDirectionVector);
479    }
480
481    //-----------------------------------------------------------------------
482    void SceneNode::setDirection(const Vector3& vec, TransformSpace relativeTo,
483        const Vector3& localDirectionVector)
484    {
485        // Do nothing if given a zero vector
486        if (vec == Vector3::ZERO) return;
487
488        // The direction we want the local direction point to
489        Vector3 targetDir = vec.normalisedCopy();
490
491        // Transform target direction to world space
492        switch (relativeTo)
493        {
494        case TS_PARENT:
495            if (mParent)
496                targetDir = mParent->_getDerivedOrientation() * targetDir;
497            break;
498        case TS_LOCAL:
499            targetDir = _getDerivedOrientation() * targetDir;
500            break;
501        }
502
503        // Calculate target orientation relative to world space
504        Quaternion targetOrientation;
505        if( mYawFixed )
506        {
507            // Calculate the quaternion for rotate local Z to target direction
508            Vector3 xVec = mYawFixedAxis.crossProduct(targetDir);
509            xVec.normalise();
510            Vector3 yVec = targetDir.crossProduct(xVec);
511            yVec.normalise();
512            Quaternion unitZToTarget = Quaternion(xVec, yVec, targetDir);
513
514            if (localDirectionVector == Vector3::NEGATIVE_UNIT_Z)
515            {
516                // Specail case for avoid calculate 180 degree turn
517                targetOrientation =
518                    Quaternion(-unitZToTarget.y, -unitZToTarget.z, unitZToTarget.w, unitZToTarget.x);
519            }
520            else
521            {
522                // Calculate the quaternion for rotate local direction to target direction
523                Quaternion localToUnitZ = localDirectionVector.getRotationTo(Vector3::UNIT_Z);
524                targetOrientation = unitZToTarget * localToUnitZ;
525            }
526        }
527        else
528        {
529            const Quaternion& currentOrient = _getDerivedOrientation();
530
531            // Get current local direction relative to world space
532            Vector3 currentDir = currentOrient * localDirectionVector;
533
534            if ((currentDir+targetDir).squaredLength() < 0.00005f)
535            {
536                // Oops, a 180 degree turn (infinite possible rotation axes)
537                // Default to yaw i.e. use current UP
538                targetOrientation =
539                    Quaternion(-currentOrient.y, -currentOrient.z, currentOrient.w, currentOrient.x);
540            }
541            else
542            {
543                // Derive shortest arc to new direction
544                Quaternion rotQuat = currentDir.getRotationTo(targetDir);
545                targetOrientation = rotQuat * currentOrient;
546            }
547        }
548
549        // Set target orientation, transformed to parent space
550        if (mParent)
551            setOrientation(mParent->_getDerivedOrientation().UnitInverse() * targetOrientation);
552        else
553            setOrientation(targetOrientation);
554    }
555    //-----------------------------------------------------------------------
556    void SceneNode::lookAt( const Vector3& targetPoint, TransformSpace relativeTo,
557        const Vector3& localDirectionVector)
558    {
559        // Calculate ourself origin relative to the given transform space
560        Vector3 origin;
561        switch (relativeTo)
562        {
563        default:    // Just in case
564        case TS_WORLD:
565            origin = _getDerivedPosition();
566            break;
567        case TS_PARENT:
568            origin = mPosition;
569            break;
570        case TS_LOCAL:
571            origin = Vector3::ZERO;
572            break;
573        }
574
575        setDirection(targetPoint - origin, relativeTo, localDirectionVector);
576    }
577    //-----------------------------------------------------------------------
578    void SceneNode::_autoTrack(void)
579    {
580        // NB assumes that all scene nodes have been updated
581        if (mAutoTrackTarget)
582        {
583            lookAt(mAutoTrackTarget->_getDerivedPosition() + mAutoTrackOffset,
584                TS_WORLD, mAutoTrackLocalDirection);
585            // update self & children
586            _update(true, true);
587        }
588    }
589    //-----------------------------------------------------------------------
590    SceneNode* SceneNode::getParentSceneNode(void) const
591    {
592        return static_cast<SceneNode*>(getParent());
593    }
594    //-----------------------------------------------------------------------
595    void SceneNode::setVisible(bool visible, bool cascade)
596    {
597        ObjectMap::iterator oi, oiend;
598        oiend = mObjectsByName.end();
599        for (oi = mObjectsByName.begin(); oi != oiend; ++oi)
600        {
601            oi->second->setVisible(visible);
602        }
603
604        if (cascade)
605        {
606            ChildNodeMap::iterator i, iend;
607            iend = mChildren.end();
608            for (i = mChildren.begin(); i != iend; ++i)
609            {
610                static_cast<SceneNode*>(i->second)->setVisible(visible, cascade);
611            }
612        }
613    }
614    //-----------------------------------------------------------------------
615    void SceneNode::flipVisibility(bool cascade)
616    {
617        ObjectMap::iterator oi, oiend;
618        oiend = mObjectsByName.end();
619        for (oi = mObjectsByName.begin(); oi != oiend; ++oi)
620        {
621            oi->second->setVisible(!oi->second->isVisible());
622        }
623
624        if (cascade)
625        {
626            ChildNodeMap::iterator i, iend;
627            iend = mChildren.end();
628            for (i = mChildren.begin(); i != iend; ++i)
629            {
630                static_cast<SceneNode*>(i->second)->flipVisibility(cascade);
631            }
632        }
633    }
634        #ifdef GTP_VISIBILITY_MODIFIED_OGRE
635        //-----------------------------------------------------------------------       
636        int SceneNode::lastVisited(void)
637        {
638                return mLastVisited;
639        }
640        //-----------------------------------------------------------------------
641        void SceneNode::setLastVisited(int frameid)
642        {
643                mLastVisited = frameid;
644        }
645        //-----------------------------------------------------------------------       
646        void SceneNode::setNodeVisible(bool visible)
647        {
648                mVisible = visible;
649        }
650        //-----------------------------------------------------------------------       
651        bool SceneNode::isNodeVisible(void)
652        {
653                return mVisible;
654        }
655        //-----------------------------------------------------------------------       
656        int SceneNode::lastRendered(void)
657        {
658                return mLastRendered;
659        }
660        //-----------------------------------------------------------------------
661        void SceneNode::setLastRendered(int frameid)
662        {
663                mLastRendered = frameid;
664        }
665        #endif //GTP_VISIBILITY_MODIFIED_OGRE
666}
Note: See TracBrowser for help on using the repository browser.