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

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