Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreRibbonTrail.cpp @ 5

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

=hoffentlich gehts jetzt

File size: 16.2 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 "OgreRibbonTrail.h"
31#include "OgreMath.h"
32#include "OgreException.h"
33#include "OgreSceneNode.h"
34#include "OgreStringConverter.h"
35
36namespace Ogre
37{
38    namespace
39    {
40        /** Controller value for pass frame time to RibbonTrail
41        */
42        class _OgrePrivate TimeControllerValue : public ControllerValue<Real>
43        {
44        protected:
45            RibbonTrail* mTrail;
46        public:
47            TimeControllerValue(RibbonTrail* r) { mTrail = r; }
48
49            Real getValue(void) const { return 0; }// not a source
50            void setValue(Real value) { mTrail->_timeUpdate(value); }
51        };
52    }
53        //-----------------------------------------------------------------------
54        //-----------------------------------------------------------------------
55        RibbonTrail::RibbonTrail(const String& name, size_t maxElements, 
56                size_t numberOfChains, bool useTextureCoords, bool useColours)
57                :BillboardChain(name, maxElements, 0, useTextureCoords, useColours, true),
58                mFadeController(0)
59        {
60                setTrailLength(100);
61                setNumberOfChains(numberOfChains);
62                mTimeControllerValue = ControllerValueRealPtr(new TimeControllerValue(this));
63
64                // use V as varying texture coord, so we can use 1D textures to 'smear'
65                setTextureCoordDirection(TCD_V);
66
67
68        }
69        //-----------------------------------------------------------------------
70        RibbonTrail::~RibbonTrail()
71        {
72                // Detach listeners
73                for (NodeList::iterator i = mNodeList.begin(); i != mNodeList.end(); ++i)
74                {
75                        (*i)->setListener(0);
76                }
77
78        if (mFadeController)
79        {
80                        // destroy controller
81                        ControllerManager::getSingleton().destroyController(mFadeController);
82        }
83
84        }
85        //-----------------------------------------------------------------------
86        void RibbonTrail::addNode(Node* n)
87        {
88                if (mNodeList.size() == mChainCount)
89                {
90                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
91                                mName + " cannot monitor any more nodes, chain count exceeded",
92                                "RibbonTrail::addNode");
93                }
94                if (n->getListener())
95                {
96                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
97                                mName + " cannot monitor node " + n->getName() + " since it already has a listener.",
98                                "RibbonTrail::addNode");
99                }
100
101        // initialise the chain
102        resetTrail(mNodeList.size(), n);
103
104                mNodeList.push_back(n);
105                n->setListener(this);
106
107        }
108        //-----------------------------------------------------------------------
109        void RibbonTrail::removeNode(Node* n)
110        {
111                NodeList::iterator i = std::find(mNodeList.begin(), mNodeList.end(), n);
112                if (i != mNodeList.end())
113                {
114                        n->setListener(0);
115                        mNodeList.erase(i);
116                }
117        }
118        //-----------------------------------------------------------------------
119        RibbonTrail::NodeIterator
120        RibbonTrail::getNodeIterator(void) const
121        {
122                return NodeIterator(mNodeList.begin(), mNodeList.end());
123        }
124        //-----------------------------------------------------------------------
125        void RibbonTrail::setTrailLength(Real len)
126        {
127                mTrailLength = len;
128                mElemLength = mTrailLength / mMaxElementsPerChain;
129                mSquaredElemLength = mElemLength * mElemLength;
130        }
131        //-----------------------------------------------------------------------
132        void RibbonTrail::setMaxChainElements(size_t maxElements)
133        {
134                BillboardChain::setMaxChainElements(maxElements);
135                mElemLength = mTrailLength / mMaxElementsPerChain;
136                mSquaredElemLength = mElemLength * mElemLength;
137
138        resetAllTrails();
139        }
140        //-----------------------------------------------------------------------
141        void RibbonTrail::setNumberOfChains(size_t numChains)
142        {
143        if (numChains < mNodeList.size())
144        {
145                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
146                                "Can't shrink the number of chains less than number of tracking nodes",
147                "RibbonTrail::setNumberOfChains");
148        }
149
150                BillboardChain::setNumberOfChains(numChains);
151
152                mInitialColour.resize(numChains, ColourValue::White);
153        mDeltaColour.resize(numChains, ColourValue::ZERO);
154                mInitialWidth.resize(numChains, 10);
155                mDeltaWidth.resize(numChains, 0);
156
157        resetAllTrails();
158        }
159        //-----------------------------------------------------------------------
160    void RibbonTrail::clearChain(size_t chainIndex)
161    {
162        BillboardChain::clearChain(chainIndex);
163
164        // Reset if we are tracking for this chain
165        if (chainIndex < mNodeList.size())
166        {
167            resetTrail(chainIndex, mNodeList[chainIndex]);
168        }
169    }
170        //-----------------------------------------------------------------------
171        void RibbonTrail::setInitialColour(size_t chainIndex, const ColourValue& col)
172        {
173                setInitialColour(chainIndex, col.r, col.g, col.b, col.a);
174        }
175        //-----------------------------------------------------------------------
176        void RibbonTrail::setInitialColour(size_t chainIndex, Real r, Real g, Real b, Real a)
177        {
178                if (chainIndex >= mChainCount)
179                {
180                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
181                                "chainIndex out of bounds", "RibbonTrail::setInitialColour");
182                }
183                mInitialColour[chainIndex].r = r;
184                mInitialColour[chainIndex].g = g;
185                mInitialColour[chainIndex].b = b;
186                mInitialColour[chainIndex].a = a;
187        }
188        //-----------------------------------------------------------------------
189        const ColourValue& RibbonTrail::getInitialColour(size_t chainIndex) const
190        {
191                if (chainIndex >= mChainCount)
192                {
193                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
194                                "chainIndex out of bounds", "RibbonTrail::getInitialColour");
195                }
196                return mInitialColour[chainIndex];
197        }
198        //-----------------------------------------------------------------------
199        void RibbonTrail::setInitialWidth(size_t chainIndex, Real width)
200        {
201                if (chainIndex >= mChainCount)
202                {
203                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
204                                "chainIndex out of bounds", "RibbonTrail::setInitialWidth");
205                }
206                mInitialWidth[chainIndex] = width;
207        }
208        //-----------------------------------------------------------------------
209        Real RibbonTrail::getInitialWidth(size_t chainIndex) const
210        {
211                if (chainIndex >= mChainCount)
212                {
213                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
214                                "chainIndex out of bounds", "RibbonTrail::getInitialWidth");
215                }
216                return mInitialWidth[chainIndex];
217        }
218        //-----------------------------------------------------------------------
219        void RibbonTrail::setColourChange(size_t chainIndex, const ColourValue& valuePerSecond)
220        {
221                setColourChange(chainIndex, 
222                        valuePerSecond.r, valuePerSecond.g, valuePerSecond.b, valuePerSecond.a);
223        }
224        //-----------------------------------------------------------------------
225        void RibbonTrail::setColourChange(size_t chainIndex, Real r, Real g, Real b, Real a)
226        {
227                if (chainIndex >= mChainCount)
228                {
229                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
230                                "chainIndex out of bounds", "RibbonTrail::setColourChange");
231                }
232                mDeltaColour[chainIndex].r = r;
233                mDeltaColour[chainIndex].g = g;
234                mDeltaColour[chainIndex].b = b;
235                mDeltaColour[chainIndex].a = a;
236
237                manageController();
238
239        }
240        //-----------------------------------------------------------------------
241        const ColourValue& RibbonTrail::getColourChange(size_t chainIndex) const
242        {
243                if (chainIndex >= mChainCount)
244                {
245                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
246                                "chainIndex out of bounds", "RibbonTrail::getColourChange");
247                }
248                return mDeltaColour[chainIndex];
249        }
250        //-----------------------------------------------------------------------
251        void RibbonTrail::setWidthChange(size_t chainIndex, Real widthDeltaPerSecond)
252        {
253                if (chainIndex >= mChainCount)
254                {
255                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
256                                "chainIndex out of bounds", "RibbonTrail::setWidthChange");
257                }
258                mDeltaWidth[chainIndex] = widthDeltaPerSecond;
259                manageController();
260        }
261        //-----------------------------------------------------------------------
262        Real RibbonTrail::getWidthChange(size_t chainIndex) const
263        {
264                if (chainIndex >= mChainCount)
265                {
266                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
267                                "chainIndex out of bounds", "RibbonTrail::getWidthChange");
268                }
269                return mDeltaWidth[chainIndex];
270
271        }
272        //-----------------------------------------------------------------------
273        void RibbonTrail::manageController(void)
274        {
275                bool needController = false;
276                for (size_t i = 0; i < mChainCount; ++i)
277                {
278                        if (mDeltaWidth[i] != 0 || mDeltaColour[i] != ColourValue::ZERO)
279                        {
280                                needController = true;
281                                break;
282                        }
283                }
284                if (!mFadeController && needController)
285                {
286                        // Set up fading via frame time controller
287                        ControllerManager& mgr = ControllerManager::getSingleton();
288                        mFadeController = mgr.createFrameTimePassthroughController(mTimeControllerValue);
289                }
290                else if (mFadeController && !needController)
291                {
292                        // destroy controller
293                        ControllerManager::getSingleton().destroyController(mFadeController);
294                        mFadeController = 0;
295                }
296
297        }
298        //-----------------------------------------------------------------------
299        void RibbonTrail::nodeUpdated(const Node* node)
300        {
301               
302                for (size_t idx = 0; idx < mNodeList.size(); ++idx)
303                {
304                        if (mNodeList[idx] == node)
305                        {
306                                updateTrail(idx, node);
307                                break;
308                        }
309                }
310        }
311        //-----------------------------------------------------------------------
312        void RibbonTrail::nodeDestroyed(const Node* node)
313        {
314                removeNode(const_cast<Node*>(node));
315
316        }
317        //-----------------------------------------------------------------------
318        void RibbonTrail::updateTrail(size_t index, const Node* node)
319        {
320                // Repeat this entire process if chain is stretched beyond its natural length
321                bool done = false;
322                while (!done)
323                {
324                        // Node has changed somehow, we're only interested in the derived position
325                        ChainSegment& seg = mChainSegmentList[index];
326                        Element& headElem = mChainElementList[seg.start + seg.head];
327                        size_t nextElemIdx = seg.head + 1;
328                        // wrap
329                        if (nextElemIdx == mMaxElementsPerChain)
330                                nextElemIdx = 0;
331                        Element& nextElem = mChainElementList[seg.start + nextElemIdx];
332
333                        // Vary the head elem, but bake new version if that exceeds element len
334                        Vector3 newPos = node->_getDerivedPosition();
335                        if (mParentNode)
336                        {
337                                // Transform position to ourself space
338                                newPos = mParentNode->_getDerivedOrientation().UnitInverse() *
339                                        (newPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();
340                        }
341                        Vector3 diff = newPos - nextElem.position;
342                        Real sqlen = diff.squaredLength();
343                        if (sqlen >= mSquaredElemLength)
344                        {
345                                // Move existing head to mElemLength
346                                Vector3 scaledDiff = diff * (mElemLength / Math::Sqrt(sqlen));
347                                headElem.position = nextElem.position + scaledDiff;
348                                // Add a new element to be the new head
349                                Element newElem(newPos, mInitialWidth[index], 0.0f, mInitialColour[index]);
350                                addChainElement(index, newElem);
351                                // alter diff to represent new head size
352                                diff = newPos - headElem.position;
353                                // check whether another step is needed or not
354                                if (diff.squaredLength() <= mSquaredElemLength)   
355                                        done = true;
356
357                        }
358                        else
359                        {
360                                // Extend existing head
361                                headElem.position = newPos;
362                                done = true;
363                        }
364
365                        // Is this segment full?
366                        if ((seg.tail + 1) % mMaxElementsPerChain == seg.head)
367                        {
368                                // If so, shrink tail gradually to match head extension
369                                Element& tailElem = mChainElementList[seg.start + seg.tail];
370                                size_t preTailIdx;
371                                if (seg.tail == 0)
372                                        preTailIdx = mMaxElementsPerChain - 1;
373                                else
374                                        preTailIdx = seg.tail - 1;
375                                Element& preTailElem = mChainElementList[seg.start + preTailIdx];
376
377                                // Measure tail diff from pretail to tail
378                                Vector3 taildiff = tailElem.position - preTailElem.position;
379                                Real taillen = taildiff.length();
380                                if (taillen > 1e-06)
381                                {
382                                        Real tailsize = mElemLength - diff.length();
383                                        taildiff *= tailsize / taillen;
384                                        tailElem.position = preTailElem.position + taildiff;
385                                }
386
387                        }
388                } // end while
389
390
391                mBoundsDirty = true;
392                // Need to dirty the parent node, but can't do it using needUpdate() here
393                // since we're in the middle of the scene graph update (node listener),
394                // so re-entrant calls don't work. Queue.
395                if (mParentNode)
396                {
397                        Node::queueNeedUpdate(getParentSceneNode());
398                }
399
400        }
401        //-----------------------------------------------------------------------
402        void RibbonTrail::_timeUpdate(Real time)
403        {
404                // Apply all segment effects
405                for (size_t s = 0; s < mChainSegmentList.size(); ++s)
406                {
407                        ChainSegment& seg = mChainSegmentList[s];
408                        if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
409                        {
410                               
411                                for(size_t e = seg.head + 1;; ++e) // until break
412                                {
413                                        e = e % mMaxElementsPerChain;
414
415                                        Element& elem = mChainElementList[seg.start + e];
416                                        elem.width = elem.width - (time * mDeltaWidth[s]);
417                                        elem.width = std::max(Real(0.0f), elem.width);
418                                        elem.colour = elem.colour - (mDeltaColour[s] * time);
419                                        elem.colour.saturate();
420
421                                        if (e == seg.tail)
422                                                break;
423                                       
424                                }
425                        }
426
427                }
428
429        }
430    //-----------------------------------------------------------------------
431    void RibbonTrail::resetTrail(size_t index, const Node* node)
432    {
433        assert(index < mChainCount);
434
435        ChainSegment& seg = mChainSegmentList[index];
436        // set up this segment
437        seg.head = seg.tail = SEGMENT_EMPTY;
438        // Create new element, v coord is always 0.0f
439        Element e(node->_getDerivedPosition(),
440            mInitialWidth[index], 0.0f, mInitialColour[index]);
441        // Add the start position
442        addChainElement(index, e);
443        // Add another on the same spot, this will extend
444        addChainElement(index, e);
445    }
446        //-----------------------------------------------------------------------
447    void RibbonTrail::resetAllTrails(void)
448    {
449        for (size_t i = 0; i < mNodeList.size(); ++i)
450        {
451            resetTrail(i, mNodeList[i]);
452        }
453    }
454        //-----------------------------------------------------------------------
455        const String& RibbonTrail::getMovableType(void) const
456        {
457                return RibbonTrailFactory::FACTORY_TYPE_NAME;
458        }
459        //-----------------------------------------------------------------------
460        //-----------------------------------------------------------------------
461        String RibbonTrailFactory::FACTORY_TYPE_NAME = "RibbonTrail";
462        //-----------------------------------------------------------------------
463        const String& RibbonTrailFactory::getType(void) const
464        {
465                return FACTORY_TYPE_NAME;
466        }
467        //-----------------------------------------------------------------------
468        MovableObject* RibbonTrailFactory::createInstanceImpl( const String& name,
469                const NameValuePairList* params)
470        {
471                size_t maxElements = 20;
472                size_t numberOfChains = 1;
473                bool useTex = true;
474                bool useCol = true;
475                // optional params
476                if (params != 0)
477                {
478                        NameValuePairList::const_iterator ni = params->find("maxElements");
479                        if (ni != params->end())
480                        {
481                                maxElements = StringConverter::parseUnsignedLong(ni->second);
482                        }
483                        ni = params->find("numberOfChains");
484                        if (ni != params->end())
485                        {
486                                numberOfChains = StringConverter::parseUnsignedLong(ni->second);
487                        }
488                        ni = params->find("useTextureCoords");
489                        if (ni != params->end())
490                        {
491                                useTex = StringConverter::parseBool(ni->second);
492                        }
493                        ni = params->find("useVertexColours");
494                        if (ni != params->end())
495                        {
496                                useCol = StringConverter::parseBool(ni->second);
497                        }
498
499                }
500
501                return new RibbonTrail(name, maxElements, numberOfChains, useTex, useCol);
502
503        }
504        //-----------------------------------------------------------------------
505        void RibbonTrailFactory::destroyInstance( MovableObject* obj)
506        {
507                delete obj;
508        }
509
510
511
512
513}
514
Note: See TracBrowser for help on using the repository browser.