source: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/src/OgreSceneNode.cpp @ 921

Revision 921, 23.5 KB checked in by mattausch, 19 years ago (diff)

added updates for visibility

Line 
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        if (obj->isAttached())
120        {
121            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
122                "Object already attached to a SceneNode or a Bone",
123                "SceneNode::attachObject");
124        }
125
126        obj->_notifyAttached(this);
127
128        // Also add to name index
129        std::pair<ObjectMap::iterator, bool> insresult =
130            mObjectsByName.insert(ObjectMap::value_type(obj->getName(), obj));
131        assert(insresult.second && "Object was not attached because an object of the "
132            "same name was already attached to this node.");
133
134        // Make sure bounds get updated (must go right to the top)
135        needUpdate();
136    }
137    //-----------------------------------------------------------------------
138    unsigned short SceneNode::numAttachedObjects(void) const
139    {
140        return static_cast< unsigned short >( mObjectsByName.size() );
141    }
142    //-----------------------------------------------------------------------
143    MovableObject* SceneNode::getAttachedObject(unsigned short index)
144    {
145        if (index < mObjectsByName.size())
146        {
147            ObjectMap::iterator i = mObjectsByName.begin();
148            // Increment (must do this one at a time)           
149            while (index--)++i;
150
151            return i->second;
152        }
153        else
154        {
155            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttachedObject");
156        }
157        return 0;
158    }
159    //-----------------------------------------------------------------------
160    MovableObject* SceneNode::getAttachedObject(const String& name)
161    {
162        // Look up
163        ObjectMap::iterator i = mObjectsByName.find(name);
164
165        if (i == mObjectsByName.end())
166        {
167            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Attached object " +
168                name + " not found.", "SceneNode::getAttachedObject");
169        }
170
171        return i->second;
172
173    }
174    //-----------------------------------------------------------------------
175    MovableObject* SceneNode::detachObject(unsigned short index)
176    {
177        MovableObject* ret;
178        if (index < mObjectsByName.size())
179        {
180
181            ObjectMap::iterator i = mObjectsByName.begin();
182            // Increment (must do this one at a time)           
183            while (index--)++i;
184
185            ret = i->second;
186            mObjectsByName.erase(i);
187            ret->_notifyAttached((SceneNode*)0);
188
189            // Make sure bounds get updated (must go right to the top)
190            needUpdate();
191
192            return ret;
193
194        }
195        else
196        {
197            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object index out of bounds.", "SceneNode::getAttchedEntity");
198        }
199        return 0;
200
201    }
202    //-----------------------------------------------------------------------
203    MovableObject* SceneNode::detachObject(const String& name)
204    {
205        ObjectMap::iterator it = mObjectsByName.find(name);
206        if (it == mObjectsByName.end())
207        {
208            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Object " + name + " is not attached "
209                "to this node.", "SceneNode::detachObject");
210        }
211        MovableObject* ret = it->second;
212        mObjectsByName.erase(it);
213        ret->_notifyAttached((SceneNode*)0);
214        // Make sure bounds get updated (must go right to the top)
215        needUpdate();
216       
217        return ret;
218
219    }
220    //-----------------------------------------------------------------------
221    void SceneNode::detachObject(MovableObject* obj)
222    {
223        ObjectMap::iterator i, iend;
224        iend = mObjectsByName.end();
225        for (i = mObjectsByName.begin(); i != iend; ++i)
226        {
227            if (i->second == obj)
228            {
229                mObjectsByName.erase(i);
230                break;
231            }
232        }
233        obj->_notifyAttached((SceneNode*)0);
234
235        // Make sure bounds get updated (must go right to the top)
236        needUpdate();
237
238    }
239    //-----------------------------------------------------------------------
240    void SceneNode::detachAllObjects(void)
241    {
242                ObjectMap::iterator itr;
243                MovableObject* ret;
244                for ( itr = mObjectsByName.begin(); itr != mObjectsByName.end(); itr++ )
245                {
246                  ret = itr->second;
247                  ret->_notifyAttached((SceneNode*)0);
248                }
249        mObjectsByName.clear();
250        // Make sure bounds get updated (must go right to the top)
251        needUpdate();
252    }
253    //-----------------------------------------------------------------------
254    void SceneNode::_updateBounds(void)
255    {
256        // Reset bounds first
257        mWorldAABB.setNull();
258
259        // Update bounds from own attached objects
260        ObjectMap::iterator i;
261        for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
262        {
263            // Merge world bounds of each object
264            mWorldAABB.merge(i->second->getWorldBoundingBox(true));
265        }
266
267        // Merge with children
268        ChildNodeMap::iterator child;
269        for (child = mChildren.begin(); child != mChildren.end(); ++child)
270        {
271            SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
272            mWorldAABB.merge(sceneChild->mWorldAABB);
273        }
274
275    }
276    //-----------------------------------------------------------------------
277    void SceneNode::_findVisibleObjects(Camera* cam, RenderQueue* queue,
278        bool includeChildren, bool displayNodes, bool onlyShadowCasters)
279    {
280        // Check self visible
281        if (!cam->isVisible(mWorldAABB))
282            return;
283
284        // Add all entities
285        ObjectMap::iterator iobj;
286        ObjectMap::iterator iobjend = mObjectsByName.end();
287        for (iobj = mObjectsByName.begin(); iobj != iobjend; ++iobj)
288        {
289            // Tell attached objects about camera position (incase any extra processing they want to do)
290            iobj->second->_notifyCurrentCamera(cam);
291            if (iobj->second->isVisible() &&
292                (!onlyShadowCasters || iobj->second->getCastShadows()))
293            {
294                iobj->second->_updateRenderQueue(queue);
295            }
296        }
297
298        if (includeChildren)
299        {
300            ChildNodeMap::iterator child, childend;
301            childend = mChildren.end();
302            for (child = mChildren.begin(); child != childend; ++child)
303            {
304                SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
305                sceneChild->_findVisibleObjects(cam, queue, includeChildren,
306                                        displayNodes, onlyShadowCasters);
307            }
308        }
309
310        if (displayNodes)
311        {
312            // Include self in the render queue
313            queue->addRenderable(this);
314        }
315
316                // Check if the bounding box should be shown.
317                // See if our flag is set or if the scene manager flag is set.
318                if (mShowBoundingBox || (mCreator && mCreator->getShowBoundingBoxes()))
319                {
320                        _addBoundingBoxToQueue(queue);
321                }
322
323
324    }
325
326
327        void SceneNode::_addBoundingBoxToQueue(RenderQueue* queue) {
328                // Create a WireBoundingBox if needed.
329                if (mWireBoundingBox == NULL) {
330                        mWireBoundingBox = new WireBoundingBox();
331                }
332                mWireBoundingBox->setupBoundingBox(mWorldAABB);
333                queue->addRenderable(mWireBoundingBox);
334        }
335
336        void SceneNode::showBoundingBox(bool bShow) {
337                mShowBoundingBox = bShow;
338        }
339
340        bool SceneNode::getShowBoundingBox() const {
341                return mShowBoundingBox;
342        }
343
344
345    //-----------------------------------------------------------------------
346    Node* SceneNode::createChildImpl(void)
347    {
348        assert(mCreator);
349        return mCreator->createSceneNode();
350    }
351    //-----------------------------------------------------------------------
352    Node* SceneNode::createChildImpl(const String& name)
353    {
354        assert(mCreator);
355        return mCreator->createSceneNode(name);
356    }
357    //-----------------------------------------------------------------------
358    AxisAlignedBox SceneNode::_getWorldAABB(void) const
359    {
360        return mWorldAABB;
361    }
362    //-----------------------------------------------------------------------
363    SceneNode::ObjectIterator SceneNode::getAttachedObjectIterator(void)
364    {
365        return ObjectIterator(mObjectsByName.begin(), mObjectsByName.end());
366    }
367        //-----------------------------------------------------------------------
368        SceneNode::ConstObjectIterator SceneNode::getAttachedObjectIterator(void) const
369        {
370                return ConstObjectIterator(mObjectsByName.begin(), mObjectsByName.end());
371        }
372    //-----------------------------------------------------------------------
373    SceneManager* SceneNode::getCreator(void) const
374    {
375        return mCreator;
376    }
377    //-----------------------------------------------------------------------
378    void SceneNode::removeAndDestroyChild(const String& name)
379    {
380        SceneNode* pChild = static_cast<SceneNode*>(getChild(name));
381        pChild->removeAndDestroyAllChildren();
382
383        removeChild(name);
384        pChild->getCreator()->destroySceneNode(name);
385
386    }
387    //-----------------------------------------------------------------------
388    void SceneNode::removeAndDestroyChild(unsigned short index)
389    {
390        SceneNode* pChild = static_cast<SceneNode*>(getChild(index));
391        pChild->removeAndDestroyAllChildren();
392
393        removeChild(index);
394        pChild->getCreator()->destroySceneNode(pChild->getName());
395    }
396    //-----------------------------------------------------------------------
397    void SceneNode::removeAndDestroyAllChildren(void)
398    {
399        ChildNodeMap::iterator i, iend;
400        iend = mChildren.end();
401        for (i = mChildren.begin(); i != iend;)
402        {
403            SceneNode* sn = static_cast<SceneNode*>(i->second);
404                        // increment iterator before destroying (iterator invalidated by
405                        // SceneManager::destroySceneNode because it causes removal from parent)
406                        ++i;
407            sn->removeAndDestroyAllChildren();
408            sn->getCreator()->destroySceneNode(sn->getName());
409        }
410            mChildren.clear();
411        needUpdate();
412    }
413    //-----------------------------------------------------------------------
414        SceneNode* SceneNode::createChildSceneNode(const Vector3& translate,
415        const Quaternion& rotate)
416        {
417                return static_cast<SceneNode*>(this->createChild(translate, rotate));
418        }
419    //-----------------------------------------------------------------------
420    SceneNode* SceneNode::createChildSceneNode(const String& name, const Vector3& translate,
421                const Quaternion& rotate)
422        {
423                return static_cast<SceneNode*>(this->createChild(name, translate, rotate));
424        }
425    //-----------------------------------------------------------------------
426    const LightList& SceneNode::findLights(Real radius) const
427    {
428        // TEMP FIX
429        // If a scene node is static and lights have moved, light list won't change
430        // can't use a simple global boolean flag since this is only called for
431        // visible nodes, so temporarily visible nodes will not be updated
432        // Since this is only called for visible nodes, skip the check for now
433        //if (mLightListDirty)
434        if (mCreator)
435        {
436            // Use SceneManager to calculate
437            mCreator->_populateLightList(this->_getDerivedPosition(), radius, mLightList);
438            mLightListDirty = false;
439        }
440        return mLightList;
441
442    }
443    //-----------------------------------------------------------------------
444    void SceneNode::setAutoTracking(bool enabled, SceneNode* target,
445        const Vector3& localDirectionVector,
446        const Vector3& offset)
447    {
448        if (enabled)
449        {
450            mAutoTrackTarget = target;
451            mAutoTrackOffset = offset;
452            mAutoTrackLocalDirection = localDirectionVector;
453        }
454        else
455        {
456            mAutoTrackTarget = 0;
457        }
458        if (mCreator)
459            mCreator->_notifyAutotrackingSceneNode(this, enabled);
460    }
461    //-----------------------------------------------------------------------
462    void SceneNode::setFixedYawAxis(bool useFixed, const Vector3& fixedAxis)
463    {
464        mYawFixed = useFixed;
465        mYawFixedAxis = fixedAxis;
466    }
467
468        //-----------------------------------------------------------------------
469        void SceneNode::yaw(const Radian& angle, TransformSpace relativeTo)
470        {
471                if (mYawFixed)
472                {
473                        rotate(mYawFixedAxis, angle, relativeTo);
474                }
475                else
476                {
477                        rotate(Vector3::UNIT_Y, angle, relativeTo);
478                }
479
480        }
481    //-----------------------------------------------------------------------
482    void SceneNode::setDirection(Real x, Real y, Real z, TransformSpace relativeTo,
483        const Vector3& localDirectionVector)
484    {
485        setDirection(Vector3(x,y,z), relativeTo, localDirectionVector);
486    }
487
488    //-----------------------------------------------------------------------
489    void SceneNode::setDirection(const Vector3& vec, TransformSpace relativeTo,
490        const Vector3& localDirectionVector)
491    {
492        // Do nothing if given a zero vector
493        if (vec == Vector3::ZERO) return;
494
495        // The direction we want the local direction point to
496        Vector3 targetDir = vec.normalisedCopy();
497
498        // Transform target direction to world space
499        switch (relativeTo)
500        {
501        case TS_PARENT:
502            if (mInheritOrientation)
503            {
504                if (mParent)
505                {
506                    targetDir = mParent->_getDerivedOrientation() * targetDir;
507                }
508            }
509            break;
510        case TS_LOCAL:
511            targetDir = _getDerivedOrientation() * targetDir;
512            break;
513        }
514
515        // Calculate target orientation relative to world space
516        Quaternion targetOrientation;
517        if( mYawFixed )
518        {
519            // Calculate the quaternion for rotate local Z to target direction
520            Vector3 xVec = mYawFixedAxis.crossProduct(targetDir);
521            xVec.normalise();
522            Vector3 yVec = targetDir.crossProduct(xVec);
523            yVec.normalise();
524            Quaternion unitZToTarget = Quaternion(xVec, yVec, targetDir);
525
526            if (localDirectionVector == Vector3::NEGATIVE_UNIT_Z)
527            {
528                // Specail case for avoid calculate 180 degree turn
529                targetOrientation =
530                    Quaternion(-unitZToTarget.y, -unitZToTarget.z, unitZToTarget.w, unitZToTarget.x);
531            }
532            else
533            {
534                // Calculate the quaternion for rotate local direction to target direction
535                Quaternion localToUnitZ = localDirectionVector.getRotationTo(Vector3::UNIT_Z);
536                targetOrientation = unitZToTarget * localToUnitZ;
537            }
538        }
539        else
540        {
541            const Quaternion& currentOrient = _getDerivedOrientation();
542
543            // Get current local direction relative to world space
544            Vector3 currentDir = currentOrient * localDirectionVector;
545
546            if ((currentDir+targetDir).squaredLength() < 0.00005f)
547            {
548                // Oops, a 180 degree turn (infinite possible rotation axes)
549                // Default to yaw i.e. use current UP
550                targetOrientation =
551                    Quaternion(-currentOrient.y, -currentOrient.z, currentOrient.w, currentOrient.x);
552            }
553            else
554            {
555                // Derive shortest arc to new direction
556                Quaternion rotQuat = currentDir.getRotationTo(targetDir);
557                targetOrientation = rotQuat * currentOrient;
558            }
559        }
560
561        // Set target orientation, transformed to parent space
562        if (mParent && mInheritOrientation)
563            setOrientation(mParent->_getDerivedOrientation().UnitInverse() * targetOrientation);
564        else
565            setOrientation(targetOrientation);
566    }
567    //-----------------------------------------------------------------------
568    void SceneNode::lookAt( const Vector3& targetPoint, TransformSpace relativeTo,
569        const Vector3& localDirectionVector)
570    {
571        // Calculate ourself origin relative to the given transform space
572        Vector3 origin;
573        switch (relativeTo)
574        {
575        default:    // Just in case
576        case TS_WORLD:
577            origin = _getDerivedPosition();
578            break;
579        case TS_PARENT:
580            origin = mPosition;
581            break;
582        case TS_LOCAL:
583            origin = Vector3::ZERO;
584            break;
585        }
586
587        setDirection(targetPoint - origin, relativeTo, localDirectionVector);
588    }
589    //-----------------------------------------------------------------------
590    void SceneNode::_autoTrack(void)
591    {
592        // NB assumes that all scene nodes have been updated
593        if (mAutoTrackTarget)
594        {
595            lookAt(mAutoTrackTarget->_getDerivedPosition() + mAutoTrackOffset,
596                TS_WORLD, mAutoTrackLocalDirection);
597            // update self & children
598            _update(true, true);
599        }
600    }
601    //-----------------------------------------------------------------------
602    SceneNode* SceneNode::getParentSceneNode(void) const
603    {
604        return static_cast<SceneNode*>(getParent());
605    }
606    //-----------------------------------------------------------------------
607    void SceneNode::setVisible(bool visible, bool cascade)
608    {
609        ObjectMap::iterator oi, oiend;
610        oiend = mObjectsByName.end();
611        for (oi = mObjectsByName.begin(); oi != oiend; ++oi)
612        {
613            oi->second->setVisible(visible);
614        }
615
616        if (cascade)
617        {
618            ChildNodeMap::iterator i, iend;
619            iend = mChildren.end();
620            for (i = mChildren.begin(); i != iend; ++i)
621            {
622                static_cast<SceneNode*>(i->second)->setVisible(visible, cascade);
623            }
624        }
625    }
626    //-----------------------------------------------------------------------
627    void SceneNode::flipVisibility(bool cascade)
628    {
629        ObjectMap::iterator oi, oiend;
630        oiend = mObjectsByName.end();
631        for (oi = mObjectsByName.begin(); oi != oiend; ++oi)
632        {
633            oi->second->setVisible(!oi->second->isVisible());
634        }
635
636        if (cascade)
637        {
638            ChildNodeMap::iterator i, iend;
639            iend = mChildren.end();
640            for (i = mChildren.begin(); i != iend; ++i)
641            {
642                static_cast<SceneNode*>(i->second)->flipVisibility(cascade);
643            }
644        }
645    }
646
647
648        #ifdef GTP_VISIBILITY_MODIFIED_OGRE
649        //-----------------------------------------------------------------------       
650        int SceneNode::lastVisited(void)
651        {
652                return mLastVisited;
653        }
654        //-----------------------------------------------------------------------
655        void SceneNode::setLastVisited(int frameid)
656        {
657                mLastVisited = frameid;
658        }
659        //-----------------------------------------------------------------------       
660        void SceneNode::setNodeVisible(bool visible)
661        {
662                mVisible = visible;
663        }
664        //-----------------------------------------------------------------------       
665        bool SceneNode::isNodeVisible(void)
666        {
667                return mVisible;
668        }
669        //-----------------------------------------------------------------------       
670        int SceneNode::lastRendered(void)
671        {
672                return mLastRendered;
673        }
674        //-----------------------------------------------------------------------
675        void SceneNode::setLastRendered(int frameid)
676        {
677                mLastRendered = frameid;
678        }
679        #endif //GTP_VISIBILITY_MODIFIED_OGRE
680}
Note: See TracBrowser for help on using the repository browser.