Coverage Report

Created: 2025-11-04 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreNode.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
30
namespace Ogre {
31
32
    Node::QueuedUpdates Node::msQueuedUpdates;
33
    //-----------------------------------------------------------------------
34
    Node::Node(const String& name)
35
0
        :mParent(0),
36
0
        mName(name),
37
0
        mNeedParentUpdate(false),
38
0
        mNeedChildUpdate(false),
39
0
        mParentNotified(false),
40
0
        mQueuedForUpdate(false),
41
0
        mInheritOrientation(true),
42
0
        mInheritScale(true),
43
0
        mCachedTransformOutOfDate(true),
44
0
        mOrientation(Quaternion::IDENTITY),
45
0
        mPosition(Vector3::ZERO),
46
0
        mScale(Vector3::UNIT_SCALE),
47
0
        mDerivedOrientation(Quaternion::IDENTITY),
48
0
        mDerivedPosition(Vector3::ZERO),
49
0
        mDerivedScale(Vector3::UNIT_SCALE),
50
0
        mInitialPosition(Vector3::ZERO),
51
0
        mInitialOrientation(Quaternion::IDENTITY),
52
0
        mInitialScale(Vector3::UNIT_SCALE),
53
0
        mListener(0)
54
0
    {
55
0
        needUpdate();
56
0
    }
57
58
    //-----------------------------------------------------------------------
59
    Node::~Node()
60
0
    {
61
        // Call listener (note, only called if there's something to do)
62
0
        if (mListener)
63
0
        {
64
0
            mListener->nodeDestroyed(this);
65
0
        }
66
67
0
        removeAllChildren();
68
0
        if(mParent)
69
0
            mParent->removeChild(this);
70
71
0
        if (mQueuedForUpdate)
72
0
        {
73
            // Erase from queued updates
74
0
            QueuedUpdates::iterator it =
75
0
                std::find(msQueuedUpdates.begin(), msQueuedUpdates.end(), this);
76
0
            assert(it != msQueuedUpdates.end());
77
0
            if (it != msQueuedUpdates.end())
78
0
            {
79
                // Optimised algorithm to erase an element from unordered vector.
80
0
                *it = msQueuedUpdates.back();
81
0
                msQueuedUpdates.pop_back();
82
0
            }
83
0
        }
84
85
0
    }
86
87
    //-----------------------------------------------------------------------
88
    void Node::setParent(Node* parent)
89
0
    {
90
0
        bool different = (parent != mParent);
91
92
0
        mParent = parent;
93
        // Request update from parent
94
0
        mParentNotified = false ;
95
0
        needUpdate();
96
97
        // Call listener (note, only called if there's something to do)
98
0
        if (mListener && different)
99
0
        {
100
0
            if (mParent)
101
0
                mListener->nodeAttached(this);
102
0
            else
103
0
                mListener->nodeDetached(this);
104
0
        }
105
106
0
    }
107
108
    //-----------------------------------------------------------------------
109
    const Affine3& Node::_getFullTransform(void) const
110
0
    {
111
0
        if (mCachedTransformOutOfDate)
112
0
        {
113
#if OGRE_NODE_INHERIT_TRANSFORM
114
            Affine3 tr;
115
            tr.makeTransform(mPosition, mScale, mOrientation);
116
117
            if(mParent == NULL)
118
            {
119
                mCachedTransform = tr;
120
            }
121
            else if(mInheritOrientation && mInheritScale) // everything is inherited
122
            {
123
                mCachedTransform = mParent->_getFullTransform() * tr;
124
            }
125
            else if(!mInheritOrientation && !mInheritScale) // only position is inherited
126
            {
127
                mCachedTransform = tr;
128
                mCachedTransform.setTrans(tr.getTrans() + mParent->_getFullTransform().getTrans());
129
            }
130
            else // shear is inherited together with orientation, controlled by mInheritOrientation
131
            {
132
                const Affine3& parentTr = mParent->_getFullTransform();
133
                Vector3 parentScale(
134
                    parentTr.transformDirection(Vector3::UNIT_X).length(),
135
                    parentTr.transformDirection(Vector3::UNIT_Y).length(),
136
                    parentTr.transformDirection(Vector3::UNIT_Z).length());
137
138
                assert(mInheritOrientation ^ mInheritScale);
139
                mCachedTransform = (mInheritOrientation ? Affine3::getScale(1.0f / parentScale)  * parentTr : Affine3::getScale(parentScale)) * tr;
140
            }
141
#else
142
            // Use derived values
143
0
            mCachedTransform.makeTransform(
144
0
                _getDerivedPosition(),
145
0
                _getDerivedScale(),
146
0
                _getDerivedOrientation());
147
0
#endif
148
0
            mCachedTransformOutOfDate = false;
149
0
        }
150
0
        return mCachedTransform;
151
0
    }
152
    //-----------------------------------------------------------------------
153
    void Node::_update(bool updateChildren, bool parentHasChanged)
154
0
    {
155
        // always clear information about parent notification
156
0
        mParentNotified = false;
157
158
        // See if we should process everyone
159
0
        if (mNeedParentUpdate || parentHasChanged)
160
0
        {
161
            // Update transforms from parent
162
0
            _updateFromParent();
163
0
        }
164
165
0
        if(updateChildren)
166
0
        {
167
0
            if (mNeedChildUpdate || parentHasChanged)
168
0
            {
169
0
                ChildNodeMap::iterator it, itend;
170
0
                itend = mChildren.end();
171
0
                for (it = mChildren.begin(); it != itend; ++it)
172
0
                {
173
0
                    Node* child = *it;
174
0
                    child->_update(true, true);
175
0
                }
176
0
            }
177
0
            else
178
0
            {
179
                // Just update selected children
180
0
                ChildUpdateSet::iterator it, itend;
181
0
                itend = mChildrenToUpdate.end();
182
0
                for(it = mChildrenToUpdate.begin(); it != itend; ++it)
183
0
                {
184
0
                    Node* child = *it;
185
0
                    child->_update(true, false);
186
0
                }
187
188
0
            }
189
190
0
            mChildrenToUpdate.clear();
191
0
            mNeedChildUpdate = false;
192
0
        }
193
0
    }
194
    //-----------------------------------------------------------------------
195
    void Node::_updateFromParent(void) const
196
0
    {
197
0
        updateFromParentImpl();
198
199
        // Call listener (note, this method only called if there's something to do)
200
0
        if (mListener)
201
0
        {
202
0
            mListener->nodeUpdated(this);
203
0
        }
204
0
    }
205
    //-----------------------------------------------------------------------
206
    void Node::updateFromParentImpl(void) const
207
0
    {
208
0
        mCachedTransformOutOfDate = true;
209
210
0
        if (mParent)
211
0
        {
212
#if OGRE_NODE_INHERIT_TRANSFORM
213
            // Decompose full transform to position, orientation and scale, shear is lost here.
214
            _getFullTransform().decomposition(mDerivedPosition, mDerivedScale, mDerivedOrientation);
215
#else
216
            // Update orientation
217
0
            const Quaternion& parentOrientation = mParent->_getDerivedOrientation();
218
0
            if (mInheritOrientation)
219
0
            {
220
                // Combine orientation with that of parent
221
0
                mDerivedOrientation = parentOrientation * mOrientation;
222
0
            }
223
0
            else
224
0
            {
225
                // No inheritance
226
0
                mDerivedOrientation = mOrientation;
227
0
            }
228
229
            // Update scale
230
0
            const Vector3& parentScale = mParent->_getDerivedScale();
231
0
            if (mInheritScale)
232
0
            {
233
                // Scale own position by parent scale, NB just combine
234
                // as equivalent axes, no shearing
235
0
                mDerivedScale = parentScale * mScale;
236
0
            }
237
0
            else
238
0
            {
239
                // No inheritance
240
0
                mDerivedScale = mScale;
241
0
            }
242
243
            // Change position vector based on parent's orientation & scale
244
0
            mDerivedPosition = parentOrientation * (parentScale * mPosition);
245
246
            // Add altered position vector to parents
247
0
            mDerivedPosition += mParent->_getDerivedPosition();
248
0
#endif
249
0
        }
250
0
        else
251
0
        {
252
            // Root node, no parent
253
0
            mDerivedOrientation = mOrientation;
254
0
            mDerivedPosition = mPosition;
255
0
            mDerivedScale = mScale;
256
0
        }
257
258
0
        mNeedParentUpdate = false;
259
260
0
    }
261
    //-----------------------------------------------------------------------
262
    Node* Node::createChild(const Vector3& inTranslate, const Quaternion& inRotate)
263
0
    {
264
0
        Node* newNode = createChildImpl();
265
0
        newNode->setPosition(inTranslate);
266
0
        newNode->setOrientation(inRotate);
267
0
        this->addChild(newNode);
268
269
0
        return newNode;
270
0
    }
271
    //-----------------------------------------------------------------------
272
    Node* Node::createChild(const String& name, const Vector3& inTranslate, const Quaternion& inRotate)
273
0
    {
274
0
        OgreAssert(!name.empty(), "");
275
0
        Node* newNode = createChildImpl(name);
276
0
        newNode->setPosition(inTranslate);
277
0
        newNode->setOrientation(inRotate);
278
0
        this->addChild(newNode);
279
280
0
        return newNode;
281
0
    }
282
    //-----------------------------------------------------------------------
283
    void Node::addChild(Node* child)
284
0
    {
285
0
        if (child->mParent)
286
0
        {
287
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
288
0
                "Node '" + child->getName() + "' already was a child of '" +
289
0
                child->mParent->getName() + "'.",
290
0
                "Node::addChild");
291
0
        }
292
293
0
        mChildren.push_back(child);
294
0
        child->setParent(this);
295
296
0
    }
297
    //-----------------------------------------------------------------------
298
    Node* Node::getChild(unsigned short index) const
299
0
    {
300
0
        if( index < mChildren.size() )
301
0
        {
302
0
            return mChildren[index];
303
0
        }
304
0
        else
305
0
            return NULL;
306
0
    }
307
    //-----------------------------------------------------------------------
308
    Node* Node::removeChild(unsigned short index)
309
0
    {
310
0
        OgreAssert(index < mChildren.size(), "");
311
312
0
        ChildNodeMap::iterator i = mChildren.begin();
313
0
        i += index;
314
0
        Node* ret = *i;
315
316
        // cancel any pending update
317
0
        cancelUpdate(ret);
318
319
0
        std::swap(*i, mChildren.back());
320
0
        mChildren.pop_back();
321
0
        ret->setParent(NULL);
322
0
        return ret;
323
0
    }
324
    //-----------------------------------------------------------------------
325
    Node* Node::removeChild(Node* child)
326
0
    {
327
0
        if (child)
328
0
        {
329
0
            ChildNodeMap::iterator i = std::find(mChildren.begin(), mChildren.end(), child);
330
0
            if(i != mChildren.end() && *i == child)
331
0
            {
332
                // cancel any pending update
333
0
                cancelUpdate(child);
334
335
0
                std::swap(*i, mChildren.back());
336
0
                mChildren.pop_back();
337
0
                child->setParent(NULL);
338
0
            }
339
0
        }
340
0
        return child;
341
0
    }
342
343
    //-----------------------------------------------------------------------
344
    void Node::setOrientation( const Quaternion & q )
345
0
    {
346
0
#ifndef OGRE_FAST_MATH
347
0
        OgreAssertDbg(!q.isNaN(), "Invalid orientation supplied as parameter");
348
0
#endif
349
0
        mOrientation = q;
350
0
        mOrientation.normalise();
351
0
        needUpdate();
352
0
    }
353
    //-----------------------------------------------------------------------
354
    void Node::setOrientation( Real w, Real x, Real y, Real z)
355
0
    {
356
0
        setOrientation(Quaternion(w, x, y, z));
357
0
    }
358
    //-----------------------------------------------------------------------
359
    void Node::resetOrientation(void)
360
0
    {
361
0
        mOrientation = Quaternion::IDENTITY;
362
0
        needUpdate();
363
0
    }
364
365
    //-----------------------------------------------------------------------
366
    void Node::setPosition(const Vector3& pos)
367
0
    {
368
0
#ifndef OGRE_FAST_MATH
369
0
        assert(!pos.isNaN() && "Invalid vector supplied as parameter");
370
0
#endif
371
0
        mPosition = pos;
372
0
        needUpdate();
373
0
    }
374
375
    //-----------------------------------------------------------------------
376
    Matrix3 Node::getLocalAxes(void) const
377
0
    {
378
0
        Matrix3 ret;
379
0
        mOrientation.ToRotationMatrix(ret);
380
0
        return ret;
381
0
    }
382
383
    //-----------------------------------------------------------------------
384
    void Node::translate(const Vector3& d, TransformSpace relativeTo)
385
0
    {
386
0
        switch(relativeTo)
387
0
        {
388
0
        case TS_LOCAL:
389
            // position is relative to parent so transform downwards
390
0
            mPosition += mOrientation * d;
391
0
            break;
392
0
        case TS_WORLD:
393
            // position is relative to parent so transform upwards
394
0
            if (mParent)
395
0
            {
396
0
                mPosition += mParent->convertWorldToLocalDirection(d, true);
397
0
            }
398
0
            else
399
0
            {
400
0
                mPosition += d;
401
0
            }
402
0
            break;
403
0
        case TS_PARENT:
404
0
            mPosition += d;
405
0
            break;
406
0
        }
407
0
        needUpdate();
408
409
0
    }
410
    //-----------------------------------------------------------------------
411
    void Node::rotate(const Quaternion& q, TransformSpace relativeTo)
412
0
    {
413
0
        switch(relativeTo)
414
0
        {
415
0
        case TS_PARENT:
416
            // Rotations are normally relative to local axes, transform up
417
0
            mOrientation = q * mOrientation;
418
0
            break;
419
0
        case TS_WORLD:
420
            // Rotations are normally relative to local axes, transform up
421
0
            mOrientation = mOrientation * _getDerivedOrientation().Inverse()
422
0
                * q * _getDerivedOrientation();
423
0
            break;
424
0
        case TS_LOCAL:
425
            // Note the order of the mult, i.e. q comes after
426
0
            mOrientation = mOrientation * q;
427
0
            break;
428
0
        }
429
430
        // Normalise quaternion to avoid drift
431
0
        mOrientation.normalise();
432
433
0
        needUpdate();
434
0
    }
435
436
    
437
    //-----------------------------------------------------------------------
438
    void Node::_setDerivedPosition( const Vector3& pos )
439
0
    {
440
        //find where the node would end up in parent's local space
441
0
        if(mParent)
442
0
            setPosition( mParent->convertWorldToLocalPosition( pos ) );
443
0
    }
444
    //-----------------------------------------------------------------------
445
    void Node::_setDerivedOrientation( const Quaternion& q )
446
0
    {
447
        //find where the node would end up in parent's local space
448
0
        if(mParent)
449
0
            setOrientation( mParent->convertWorldToLocalOrientation( q ) );
450
0
    }
451
452
    //-----------------------------------------------------------------------
453
    const Quaternion & Node::_getDerivedOrientation(void) const
454
0
    {
455
0
        if (mNeedParentUpdate)
456
0
        {
457
0
            _updateFromParent();
458
0
        }
459
0
        return mDerivedOrientation;
460
0
    }
461
    //-----------------------------------------------------------------------
462
    const Vector3 & Node::_getDerivedPosition(void) const
463
0
    {
464
0
        if (mNeedParentUpdate)
465
0
        {
466
0
            _updateFromParent();
467
0
        }
468
0
        return mDerivedPosition;
469
0
    }
470
    //-----------------------------------------------------------------------
471
    const Vector3 & Node::_getDerivedScale(void) const
472
0
    {
473
0
        if (mNeedParentUpdate)
474
0
        {
475
0
            _updateFromParent();
476
0
        }
477
0
        return mDerivedScale;
478
0
    }
479
    //-----------------------------------------------------------------------
480
    Vector3 Node::convertWorldToLocalPosition( const Vector3 &worldPos )
481
0
    {
482
0
        if (mNeedParentUpdate)
483
0
        {
484
0
            _updateFromParent();
485
0
        }
486
#if OGRE_NODE_INHERIT_TRANSFORM
487
        return _getFullTransform().inverse() * worldPos;
488
#else
489
0
        return mDerivedOrientation.Inverse() * (worldPos - mDerivedPosition) / mDerivedScale;
490
0
#endif
491
0
    }
492
    //-----------------------------------------------------------------------
493
    Vector3 Node::convertLocalToWorldPosition( const Vector3 &localPos )
494
0
    {
495
0
        if (mNeedParentUpdate)
496
0
        {
497
0
            _updateFromParent();
498
0
        }
499
0
        return _getFullTransform() * localPos;
500
0
    }
501
    //-----------------------------------------------------------------------
502
    Vector3 Node::convertWorldToLocalDirection( const Vector3 &worldDir, bool useScale )
503
0
    {
504
0
        if (mNeedParentUpdate)
505
0
        {
506
0
            _updateFromParent();
507
0
        }
508
509
0
        return useScale ? 
510
#if OGRE_NODE_INHERIT_TRANSFORM
511
            _getFullTransform().inverseAffine().transformDirectionAffine(worldDir) :
512
            mDerivedOrientation.Inverse() * worldDir;
513
#else
514
0
            mDerivedOrientation.Inverse() * worldDir / mDerivedScale :
515
0
            mDerivedOrientation.Inverse() * worldDir;
516
0
#endif
517
0
    }
518
    //-----------------------------------------------------------------------
519
    Vector3 Node::convertLocalToWorldDirection( const Vector3 &localDir, bool useScale )
520
0
    {
521
0
        if (mNeedParentUpdate)
522
0
        {
523
0
            _updateFromParent();
524
0
        }
525
0
        return useScale ? _getFullTransform().linear() * localDir : mDerivedOrientation * localDir;
526
0
    }
527
    //-----------------------------------------------------------------------
528
    Quaternion Node::convertWorldToLocalOrientation( const Quaternion &worldOrientation )
529
0
    {
530
0
        if (mNeedParentUpdate)
531
0
        {
532
0
            _updateFromParent();
533
0
        }
534
0
        return mDerivedOrientation.Inverse() * worldOrientation;
535
0
    }
536
    //-----------------------------------------------------------------------
537
    Quaternion Node::convertLocalToWorldOrientation( const Quaternion &localOrientation )
538
0
    {
539
0
        if (mNeedParentUpdate)
540
0
        {
541
0
            _updateFromParent();
542
0
        }
543
0
        return mDerivedOrientation * localOrientation;
544
545
0
    }
546
    //-----------------------------------------------------------------------
547
    void Node::removeAllChildren(void)
548
0
    {
549
0
        for (auto *c : mChildren)
550
0
        {
551
0
            c->setParent(0);
552
0
        }
553
0
        mChildren.clear();
554
0
        mChildrenToUpdate.clear();
555
0
    }
556
    //-----------------------------------------------------------------------
557
    void Node::setScale(const Vector3& inScale)
558
0
    {
559
0
#ifndef OGRE_FAST_MATH
560
0
        assert(!inScale.isNaN() && "Invalid vector supplied as parameter");
561
0
#endif
562
0
        mScale = inScale;
563
0
        needUpdate();
564
0
    }
565
    //-----------------------------------------------------------------------
566
    void Node::setInheritOrientation(bool inherit)
567
0
    {
568
0
        mInheritOrientation = inherit;
569
0
        needUpdate();
570
0
    }
571
    //-----------------------------------------------------------------------
572
    void Node::setInheritScale(bool inherit)
573
0
    {
574
0
        mInheritScale = inherit;
575
0
        needUpdate();
576
0
    }
577
    //-----------------------------------------------------------------------
578
    void Node::scale(const Vector3& inScale)
579
0
    {
580
0
        mScale = mScale * inScale;
581
0
        needUpdate();
582
583
0
    }
584
    //-----------------------------------------------------------------------
585
    void Node::scale(Real x, Real y, Real z)
586
0
    {
587
0
        mScale.x *= x;
588
0
        mScale.y *= y;
589
0
        mScale.z *= z;
590
0
        needUpdate();
591
592
0
    }
593
    //-----------------------------------------------------------------------
594
    void Node::setInitialState(void)
595
0
    {
596
0
        mInitialPosition = mPosition;
597
0
        mInitialOrientation = mOrientation;
598
0
        mInitialScale = mScale;
599
0
    }
600
    //-----------------------------------------------------------------------
601
    void Node::resetToInitialState(void)
602
0
    {
603
0
        mPosition = mInitialPosition;
604
0
        mOrientation = mInitialOrientation;
605
0
        mScale = mInitialScale;
606
607
0
        needUpdate();
608
0
    }
609
    //-----------------------------------------------------------------------
610
    struct NodeNameExists {
611
        const String& name;
612
0
        bool operator()(const Node* mo) {
613
0
            return mo->getName() == name;
614
0
        }
615
    };
616
    Node* Node::getChild(const String& name) const
617
0
    {
618
0
        NodeNameExists pred = {name};
619
0
        ChildNodeMap::const_iterator i = std::find_if(mChildren.begin(), mChildren.end(), pred);
620
621
0
        if (i == mChildren.end())
622
0
        {
623
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Child node named " + name +
624
0
                " does not exist.", "Node::getChild");
625
0
        }
626
627
0
        return *i;
628
0
    }
629
    //-----------------------------------------------------------------------
630
    Node* Node::removeChild(const String& name)
631
0
    {
632
0
        OgreAssert(!name.empty(), "");
633
0
        NodeNameExists pred = {name};
634
0
        ChildNodeMap::iterator i = std::find_if(mChildren.begin(), mChildren.end(), pred);
635
636
0
        if (i == mChildren.end())
637
0
        {
638
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Child node named " + name +
639
0
                " does not exist.", "Node::removeChild");
640
0
        }
641
642
0
        Node* ret = *i;
643
644
        // Cancel any pending update
645
0
        cancelUpdate(ret);
646
0
        std::swap(*i, mChildren.back());
647
0
        mChildren.pop_back();
648
0
        ret->setParent(NULL);
649
650
0
        return ret;
651
652
653
0
    }
654
    //-----------------------------------------------------------------------
655
    Node::ChildNodeIterator Node::getChildIterator(void)
656
0
    {
657
0
        return ChildNodeIterator(mChildren.begin(), mChildren.end());
658
0
    }
659
    //-----------------------------------------------------------------------
660
    Node::ConstChildNodeIterator Node::getChildIterator(void) const
661
0
    {
662
0
        return ConstChildNodeIterator(mChildren.begin(), mChildren.end());
663
0
    }
664
    //-----------------------------------------------------------------------
665
    Real Node::getSquaredViewDepth(const Camera* cam) const
666
0
    {
667
0
        Vector3 diff = _getDerivedPosition() - cam->getDerivedPosition();
668
0
        Vector3 zAxis = cam->getDerivedDirection();
669
670
        // NB use squared length to avoid square root
671
0
        return cam->getSortMode() == SM_DISTANCE ? diff.squaredLength() : Math::Sqr(zAxis.dotProduct(diff));
672
0
    }
673
    //-----------------------------------------------------------------------
674
    void Node::needUpdate(bool forceParentUpdate)
675
0
    {
676
677
0
        mNeedParentUpdate = true;
678
0
        mNeedChildUpdate = true;
679
0
        mCachedTransformOutOfDate = true;
680
681
        // Make sure we're not root and parent hasn't been notified before
682
0
        if (mParent && (!mParentNotified || forceParentUpdate))
683
0
        {
684
0
            mParent->requestUpdate(this, forceParentUpdate);
685
0
            mParentNotified = true ;
686
0
        }
687
688
        // all children will be updated
689
0
        mChildrenToUpdate.clear();
690
0
    }
691
    //-----------------------------------------------------------------------
692
    void Node::requestUpdate(Node* child, bool forceParentUpdate)
693
0
    {
694
        // If we're already going to update everything this doesn't matter
695
0
        if (mNeedChildUpdate)
696
0
        {
697
0
            return;
698
0
        }
699
700
0
        mChildrenToUpdate.insert(child);
701
        // Request selective update of me, if we didn't do it before
702
0
        if (mParent && (!mParentNotified || forceParentUpdate))
703
0
        {
704
0
            mParent->requestUpdate(this, forceParentUpdate);
705
0
            mParentNotified = true ;
706
0
        }
707
708
0
    }
709
    //-----------------------------------------------------------------------
710
    void Node::cancelUpdate(Node* child)
711
0
    {
712
0
        mChildrenToUpdate.erase(child);
713
714
        // Propagate this up if we're done
715
0
        if (mChildrenToUpdate.empty() && mParent && !mNeedChildUpdate)
716
0
        {
717
0
            mParent->cancelUpdate(this);
718
0
            mParentNotified = false ;
719
0
        }
720
0
    }
721
    //-----------------------------------------------------------------------
722
    void Node::queueNeedUpdate(Node* n)
723
0
    {
724
        // Don't queue the node more than once
725
0
        if (!n->mQueuedForUpdate)
726
0
        {
727
0
            n->mQueuedForUpdate = true;
728
0
            msQueuedUpdates.push_back(n);
729
0
        }
730
0
    }
731
    //-----------------------------------------------------------------------
732
    void Node::processQueuedUpdates(void)
733
0
    {
734
0
        for (auto *n : msQueuedUpdates)
735
0
        {
736
            // Update, and force parent update since chances are we've ended
737
            // up with some mixed state in there due to re-entrancy
738
0
            n->mQueuedForUpdate = false;
739
0
            n->needUpdate(true);
740
0
        }
741
0
        msQueuedUpdates.clear();
742
0
    }
743
}
744