Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/OgreMain/src/OgreSceneNode.cpp @ 48

Last change on this file since 48 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

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