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

Revision 692, 22.1 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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