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

Revision 692, 49.6 KB checked in by mattausch, 19 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
27#include "OgreBillboardSet.h"
28
29#include "OgreBillboard.h"
30#include "OgreMaterialManager.h"
31#include "OgreHardwareBufferManager.h"
32#include "OgreCamera.h"
33#include "OgreMath.h"
34#include "OgreSphere.h"
35#include "OgreRoot.h"
36#include "OgreException.h"
37#include "OgreStringConverter.h"
38#include "OgreLogManager.h"
39#include <algorithm>
40
41namespace Ogre {
42    // Init statics
43    RadixSort<BillboardSet::ActiveBillboardList, Billboard*, float> BillboardSet::mRadixSorter;
44
45    //-----------------------------------------------------------------------
46    BillboardSet::BillboardSet() :
47        mOriginType( BBO_CENTER ),
48        mRotationType( BBR_TEXCOORD ),
49        mAllDefaultSize( true ),
50        mAutoExtendPool( true ),
51        mSortingEnabled(false),
52        mAccurateFacing(false),
53        mAllDefaultRotation(true),
54        mWorldSpace(false),
55        mVertexData(0),
56        mIndexData(0),
57        mCullIndividual( false ),
58        mBillboardType(BBT_POINT),
59        mCommonDirection(Ogre::Vector3::UNIT_Z),
60        mCommonUpVector(Vector3::UNIT_Y),
61        mPointRendering(false),
62        mBuffersCreated(false),
63        mPoolSize(0),
64                mExternalData(false)
65    {
66        setDefaultDimensions( 100, 100 );
67        setMaterialName( "BaseWhite" );
68        mCastShadows = false;
69        setTextureStacksAndSlices( 1, 1 );
70    }
71
72    //-----------------------------------------------------------------------
73    BillboardSet::BillboardSet(
74        const String& name,
75        unsigned int poolSize,
76        bool externalData) :
77        MovableObject(name),
78        mOriginType( BBO_CENTER ),
79        mRotationType( BBR_TEXCOORD ),
80        mAllDefaultSize( true ),
81        mAutoExtendPool( true ),
82        mSortingEnabled(false),
83        mAccurateFacing(false),
84        mAllDefaultRotation(true),
85        mWorldSpace(false),
86        mVertexData(0),
87        mIndexData(0),
88        mCullIndividual( false ),
89        mBillboardType(BBT_POINT),
90        mCommonDirection(Ogre::Vector3::UNIT_Z),
91        mCommonUpVector(Vector3::UNIT_Y),
92                mPointRendering(false),
93        mBuffersCreated(false),
94        mPoolSize(poolSize),
95        mExternalData(externalData)
96    {
97        setDefaultDimensions( 100, 100 );
98        setMaterialName( "BaseWhite" );
99        setPoolSize( poolSize );
100        mCastShadows = false;
101        setTextureStacksAndSlices( 1, 1 );
102    }
103    //-----------------------------------------------------------------------
104    BillboardSet::~BillboardSet()
105    {
106        // Free pool items
107        BillboardPool::iterator i;
108        for (i = mBillboardPool.begin(); i != mBillboardPool.end(); ++i)
109        {
110            delete *i;
111        }
112
113        // Delete shared buffers
114                _destroyBuffers();
115    }
116    //-----------------------------------------------------------------------
117    Billboard* BillboardSet::createBillboard(
118        const Vector3& position,
119        const ColourValue& colour )
120    {
121        if( mFreeBillboards.empty() )
122        {
123            if( mAutoExtendPool )
124            {
125                setPoolSize( getPoolSize() * 2 );
126            }
127            else
128            {
129                return 0;
130            }
131        }
132
133        // Get a new billboard
134        Billboard* newBill = mFreeBillboards.front();
135                mActiveBillboards.splice(
136                        mActiveBillboards.end(), mFreeBillboards, mFreeBillboards.begin());
137        newBill->setPosition(position);
138        newBill->setColour(colour);
139        newBill->mDirection = Vector3::ZERO;
140        newBill->setRotation(Radian(0));
141        newBill->setTexcoordIndex(0);
142        newBill->resetDimensions();
143        newBill->_notifyOwner(this);
144
145                // Merge into bounds
146                Real adjust = std::max(mDefaultWidth, mDefaultHeight);
147        Vector3 vecAdjust(adjust, adjust, adjust);
148                Vector3 newMin = position - vecAdjust;
149                Vector3 newMax = position + vecAdjust;
150
151        mAABB.merge(newMin);
152        mAABB.merge(newMax);
153
154                Real sqlen = std::max(newMin.squaredLength(), newMax.squaredLength());
155                mBoundingRadius = std::max(mBoundingRadius, Math::Sqrt(sqlen));
156
157        return newBill;
158    }
159
160    //-----------------------------------------------------------------------
161    Billboard* BillboardSet::createBillboard(
162        Real x, Real y, Real z,
163        const ColourValue& colour )
164    {
165        return createBillboard( Vector3( x, y, z ), colour );
166    }
167
168    //-----------------------------------------------------------------------
169    int BillboardSet::getNumBillboards(void) const
170    {
171        return static_cast< int >( mActiveBillboards.size() );
172    }
173
174    //-----------------------------------------------------------------------
175    void BillboardSet::clear()
176    {
177                // Insert actives into free list
178                mFreeBillboards.insert(mFreeBillboards.end(), mActiveBillboards.begin(), mActiveBillboards.end());
179
180                // Remove all active instances
181        mActiveBillboards.clear();
182    }
183
184    //-----------------------------------------------------------------------
185    Billboard* BillboardSet::getBillboard( unsigned int index ) const
186    {
187        assert(
188            index < mActiveBillboards.size() &&
189            "Billboard index out of bounds." );
190
191        /* We can't access it directly, so we check wether it's in the first
192           or the second half, then we start either from the beginning or the
193           end of the list
194        */
195        ActiveBillboardList::const_iterator it;
196        if( index >= ( mActiveBillboards.size() >> 1 ) )
197        {
198                        index = static_cast<unsigned int>(mActiveBillboards.size()) - index;
199            for( it = mActiveBillboards.end(); index; --index, --it );
200        }
201        else
202        {
203            for( it = mActiveBillboards.begin(); index; --index, ++it );
204        }
205
206        return *it;
207    }
208
209    //-----------------------------------------------------------------------
210    void BillboardSet::removeBillboard(unsigned int index)
211    {
212        assert(
213            index < mActiveBillboards.size() &&
214            "Billboard index out of bounds." );
215
216        /* We can't access it directly, so we check wether it's in the first
217           or the second half, then we start either from the beginning or the
218           end of the list.
219           We then remove the billboard form the 'used' list and add it to
220           the 'free' list.
221        */
222        ActiveBillboardList::iterator it;
223        if( index >= ( mActiveBillboards.size() >> 1 ) )
224        {
225                        index = static_cast<unsigned int>(mActiveBillboards.size()) - index;
226            for( it = mActiveBillboards.end(); index; --index, --it );
227        }
228        else
229        {
230            for( it = mActiveBillboards.begin(); index; --index, ++it );
231        }
232
233        mFreeBillboards.push_back( *it );
234        mActiveBillboards.erase( it );
235    }
236
237    //-----------------------------------------------------------------------
238    void BillboardSet::removeBillboard( Billboard* pBill )
239    {
240        mActiveBillboards.remove( pBill );
241        mFreeBillboards.push_back( pBill );
242    }
243
244    //-----------------------------------------------------------------------
245    void BillboardSet::setBillboardOrigin( BillboardOrigin origin )
246    {
247        mOriginType = origin;
248    }
249
250    //-----------------------------------------------------------------------
251    BillboardOrigin BillboardSet::getBillboardOrigin(void) const
252    {
253        return mOriginType;
254    }
255
256    //-----------------------------------------------------------------------
257    void BillboardSet::setBillboardRotationType(BillboardRotationType rotationType)
258    {
259        mRotationType = rotationType;
260    }
261    //-----------------------------------------------------------------------
262    BillboardRotationType BillboardSet::getBillboardRotationType(void) const
263    {
264        return mRotationType;
265    }
266    //-----------------------------------------------------------------------
267    void BillboardSet::setDefaultDimensions( Real width, Real height )
268    {
269        mDefaultWidth = width;
270        mDefaultHeight = height;
271    }
272    //-----------------------------------------------------------------------
273    void BillboardSet::setDefaultWidth(Real width)
274    {
275        mDefaultWidth = width;
276    }
277    //-----------------------------------------------------------------------
278    Real BillboardSet::getDefaultWidth(void) const
279    {
280        return mDefaultWidth;
281    }
282    //-----------------------------------------------------------------------
283    void BillboardSet::setDefaultHeight(Real height)
284    {
285        mDefaultHeight = height;
286    }
287    //-----------------------------------------------------------------------
288    Real BillboardSet::getDefaultHeight(void) const
289    {
290        return mDefaultHeight;
291    }
292    //-----------------------------------------------------------------------
293    void BillboardSet::setMaterialName( const String& name )
294    {
295        mMaterialName = name;
296
297        mpMaterial = MaterialManager::getSingleton().getByName(name);
298
299                if (mpMaterial.isNull())
300                        OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find material " + name,
301                                "BillboardSet::setMaterialName" );
302
303        /* Ensure that the new material was loaded (will not load again if
304           already loaded anyway)
305        */
306        mpMaterial->load();
307    }
308
309    //-----------------------------------------------------------------------
310    const String& BillboardSet::getMaterialName(void) const
311    {
312        return mMaterialName;
313    }
314
315    //-----------------------------------------------------------------------
316    void BillboardSet::_sortBillboards( Camera* cam)
317    {
318        switch (_getSortMode())
319        {
320        case SM_DIRECTION:
321            mRadixSorter.sort(mActiveBillboards, SortByDirectionFunctor(-mCamDir));
322            break;
323        case SM_DISTANCE:
324            mRadixSorter.sort(mActiveBillboards, SortByDistanceFunctor(mCamPos));
325            break;
326        }
327    }
328    BillboardSet::SortByDirectionFunctor::SortByDirectionFunctor(const Vector3& dir)
329        : sortDir(dir)
330    {
331    }
332    float BillboardSet::SortByDirectionFunctor::operator()(Billboard* bill) const
333    {
334        return sortDir.dotProduct(bill->getPosition());
335    }
336    BillboardSet::SortByDistanceFunctor::SortByDistanceFunctor(const Vector3& pos)
337        : sortPos(pos)
338    {
339    }
340    float BillboardSet::SortByDistanceFunctor::operator()(Billboard* bill) const
341    {
342        // Sort descending by squared distance
343        return - (sortPos - bill->getPosition()).squaredLength();
344    }
345    //-----------------------------------------------------------------------
346    SortMode BillboardSet::_getSortMode(void) const
347    {
348        // Need to sort by distance if we're using accurate facing, or perpendicular billboard type.
349        if (mAccurateFacing ||
350            mBillboardType == BBT_PERPENDICULAR_SELF ||
351            mBillboardType == BBT_PERPENDICULAR_COMMON)
352        {
353            return SM_DISTANCE;
354        }
355        else
356        {
357            return SM_DIRECTION;
358        }
359    }
360    //-----------------------------------------------------------------------
361    void BillboardSet::_notifyCurrentCamera( Camera* cam )
362    {
363                MovableObject::_notifyCurrentCamera(cam);
364
365        mCurrentCamera = cam;
366
367        // Calculate camera orientation and position
368        mCamQ = mCurrentCamera->getDerivedOrientation();
369        mCamPos = mCurrentCamera->getDerivedPosition();
370        if (!mWorldSpace)
371        {
372            // Default behaviour is that billboards are in local node space
373            // so orientation of camera (in world space) must be reverse-transformed
374            // into node space
375            mCamQ = mParentNode->_getDerivedOrientation().UnitInverse() * mCamQ;
376            mCamPos = mParentNode->_getDerivedOrientation().UnitInverse() *
377                (mCamPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();
378        }
379
380        // Camera direction points down -Z
381        mCamDir = mCamQ * Vector3::NEGATIVE_UNIT_Z;
382    }
383    //-----------------------------------------------------------------------
384    void BillboardSet::beginBillboards(void)
385    {
386        /* Generate the vertices for all the billboards relative to the camera
387           Also take the opportunity to update the vertex colours
388           May as well do it here to save on loops elsewhere
389        */
390
391        /* NOTE: most engines generate world coordinates for the billboards
392           directly, taking the world axes of the camera as offsets to the
393           center points. I take a different approach, reverse-transforming
394           the camera world axes into local billboard space.
395           Why?
396           Well, it's actually more efficient this way, because I only have to
397           reverse-transform using the billboardset world matrix (inverse)
398           once, from then on it's simple additions (assuming identically
399           sized billboards). If I transformed every billboard center by it's
400           world transform, that's a matrix multiplication per billboard
401           instead.
402           I leave the final transform to the render pipeline since that can
403           use hardware TnL if it is available.
404        */
405
406        // create vertex and index buffers if they haven't already been
407        if(!mBuffersCreated)
408            _createBuffers();
409
410                // Only calculate vertex offets et al if we're not point rendering
411                if (!mPointRendering)
412                {
413
414                        // Get offsets for origin type
415                        getParametricOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff);
416
417                        // Generate axes etc up-front if not oriented per-billboard
418                        if (mBillboardType != BBT_ORIENTED_SELF &&
419                                mBillboardType != BBT_PERPENDICULAR_SELF &&
420                                !mAccurateFacing)
421                        {
422                                genBillboardAxes(&mCamX, &mCamY);
423
424                                /* If all billboards are the same size we can precalculate the
425                                   offsets and just use '+' instead of '*' for each billboard,
426                                   and it should be faster.
427                                */
428                                genVertOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff,
429                                        mDefaultWidth, mDefaultHeight, mCamX, mCamY, mVOffset);
430
431                        }
432                }
433
434        // Init num visible
435        mNumVisibleBillboards = 0;
436
437        // Lock the buffer
438        mLockPtr = static_cast<float*>(
439            mMainBuf->lock(HardwareBuffer::HBL_DISCARD) );
440
441    }
442    //-----------------------------------------------------------------------
443    void BillboardSet::injectBillboard(const Billboard& bb)
444    {
445        // Skip if not visible (NB always true if not bounds checking individual billboards)
446        if (!billboardVisible(mCurrentCamera, bb)) return;
447
448        if (!mPointRendering &&
449                        (mBillboardType == BBT_ORIENTED_SELF ||
450            mBillboardType == BBT_PERPENDICULAR_SELF ||
451            mAccurateFacing))
452        {
453            // Have to generate axes & offsets per billboard
454            genBillboardAxes(&mCamX, &mCamY, &bb);
455        }
456
457                // If they're all the same size or we're point rendering
458        if( mAllDefaultSize || mPointRendering)
459        {
460            /* No per-billboard checking, just blast through.
461            Saves us an if clause every billboard which may
462            make a difference.
463            */
464
465            if (!mPointRendering &&
466                                (mBillboardType == BBT_ORIENTED_SELF ||
467                        mBillboardType == BBT_PERPENDICULAR_SELF ||
468                        mAccurateFacing))
469            {
470                genVertOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff,
471                    mDefaultWidth, mDefaultHeight, mCamX, mCamY, mVOffset);
472            }
473            genVertices(mVOffset, bb);
474        }
475        else // not all default size and not point rendering
476        {
477            Vector3 vOwnOffset[4];
478            // If it has own dimensions, or self-oriented, gen offsets
479            if (mBillboardType == BBT_ORIENTED_SELF ||
480                mBillboardType == BBT_PERPENDICULAR_SELF ||
481                bb.mOwnDimensions ||
482                mAccurateFacing)
483            {
484                // Generate using own dimensions
485                genVertOffsets(mLeftOff, mRightOff, mTopOff, mBottomOff,
486                    bb.mWidth, bb.mHeight, mCamX, mCamY, vOwnOffset);
487                // Create vertex data
488                genVertices(vOwnOffset, bb);
489            }
490            else // Use default dimension, already computed before the loop, for faster creation
491            {
492                genVertices(mVOffset, bb);
493            }
494        }
495        // Increment visibles
496        mNumVisibleBillboards++;
497    }
498    //-----------------------------------------------------------------------
499    void BillboardSet::endBillboards(void)
500    {
501        mMainBuf->unlock();
502    }
503        //-----------------------------------------------------------------------
504        void BillboardSet::setBounds(const AxisAlignedBox& box, Real radius)
505        {
506                mAABB = box;
507                mBoundingRadius = radius;
508        }
509    //-----------------------------------------------------------------------
510    void BillboardSet::_updateBounds(void)
511    {
512        if (mActiveBillboards.empty())
513        {
514            // No billboards, null bbox
515            mAABB.setNull();
516                        mBoundingRadius = 0.0f;
517        }
518        else
519        {
520                        Real maxSqLen = -1.0f;
521
522            Vector3 min(Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY);
523            Vector3 max(Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY);
524            ActiveBillboardList::iterator i, iend;
525
526            iend = mActiveBillboards.end();
527            for (i = mActiveBillboards.begin(); i != iend; ++i)
528            {
529                const Vector3& pos = (*i)->getPosition();
530                min.makeFloor(pos);
531                max.makeCeil(pos);
532
533                                maxSqLen = std::max(maxSqLen, pos.squaredLength());
534            }
535            // Adjust for billboard size
536            Real adjust = std::max(mDefaultWidth, mDefaultHeight);
537            Vector3 vecAdjust(adjust, adjust, adjust);
538            min -= vecAdjust;
539            max += vecAdjust;
540
541            mAABB.setExtents(min, max);
542                        mBoundingRadius = Math::Sqrt(maxSqLen);
543
544        }
545
546        if (mParentNode)
547            mParentNode->needUpdate();
548
549    }
550    //-----------------------------------------------------------------------
551    const AxisAlignedBox& BillboardSet::getBoundingBox(void) const
552    {
553        return mAABB;
554    }
555
556    //-----------------------------------------------------------------------
557    void BillboardSet::_updateRenderQueue(RenderQueue* queue)
558    {
559        // If we're driving this from our own data, update geometry now
560        if (!mExternalData)
561        {
562            if (mSortingEnabled)
563            {
564                _sortBillboards(mCurrentCamera);
565            }
566
567            beginBillboards();
568            ActiveBillboardList::iterator it;
569            for(it = mActiveBillboards.begin();
570                it != mActiveBillboards.end();
571                ++it )
572            {
573                injectBillboard(*(*it));
574            }
575            endBillboards();
576        }
577
578        //only set the render queue group if it has been explicitly set.
579        if( mRenderQueueIDSet )
580        {
581           queue->addRenderable(this, mRenderQueueID);
582        } else {
583           queue->addRenderable(this);
584        }
585
586    }
587
588    //-----------------------------------------------------------------------
589    const MaterialPtr& BillboardSet::getMaterial(void) const
590    {
591        return mpMaterial;
592    }
593
594    //-----------------------------------------------------------------------
595    void BillboardSet::getRenderOperation(RenderOperation& op)
596    {
597        op.vertexData = mVertexData;
598        op.vertexData->vertexStart = 0;
599
600                if (mPointRendering)
601                {
602                        op.operationType = RenderOperation::OT_POINT_LIST;
603            op.useIndexes = false;
604                        op.indexData = 0;
605                        op.vertexData->vertexCount = mNumVisibleBillboards;
606                }
607                else
608                {
609                        op.operationType = RenderOperation::OT_TRIANGLE_LIST;
610            op.useIndexes = true;
611
612            op.vertexData->vertexCount = mNumVisibleBillboards * 4;
613
614                op.indexData = mIndexData;
615            op.indexData->indexCount = mNumVisibleBillboards * 6;
616                op.indexData->indexStart = 0;
617                }
618    }
619
620    //-----------------------------------------------------------------------
621    void BillboardSet::getWorldTransforms( Matrix4* xform ) const
622    {
623        if (mWorldSpace)
624        {
625            *xform = Matrix4::IDENTITY;
626        }
627        else
628        {
629            *xform = _getParentNodeFullTransform();
630        }
631    }
632
633    //-----------------------------------------------------------------------
634    const Quaternion& BillboardSet::getWorldOrientation(void) const
635    {
636        return mParentNode->_getDerivedOrientation();
637    }
638
639    //-----------------------------------------------------------------------
640    const Vector3& BillboardSet::getWorldPosition(void) const
641    {
642        return mParentNode->_getDerivedPosition();
643    }
644
645    //-----------------------------------------------------------------------
646    void BillboardSet::setAutoextend( bool autoextend )
647    {
648        mAutoExtendPool = autoextend;
649    }
650
651    //-----------------------------------------------------------------------
652    bool BillboardSet::getAutoextend(void) const
653    {
654        return mAutoExtendPool;
655    }
656
657    //-----------------------------------------------------------------------
658    void BillboardSet::setSortingEnabled( bool sortenable )
659    {
660        mSortingEnabled = sortenable;
661    }
662
663    //-----------------------------------------------------------------------
664    bool BillboardSet::getSortingEnabled(void) const
665    {
666        return mSortingEnabled;
667    }
668
669    //-----------------------------------------------------------------------
670    void BillboardSet::setPoolSize( unsigned int size )
671    {
672        // If we're driving this from our own data, allocate billboards
673        if (!mExternalData)
674        {
675            // Never shrink below size()
676            size_t currSize = mBillboardPool.size();
677            if (currSize >= size)
678                return;
679
680            this->increasePool(size);
681
682            for( size_t i = currSize; i < size; ++i )
683            {
684                // Add new items to the queue
685                mFreeBillboards.push_back( mBillboardPool[i] );
686            }
687        }
688
689        mPoolSize = size;
690
691                _destroyBuffers();
692    }
693
694    //-----------------------------------------------------------------------
695    void BillboardSet::_createBuffers(void)
696    {
697        /* Allocate / reallocate vertex data
698           Note that we allocate enough space for ALL the billboards in the pool, but only issue
699           rendering operations for the sections relating to the active billboards
700        */
701
702        /* Alloc positions   ( 1 or 4 verts per billboard, 3 components )
703                 colours     ( 1 x RGBA per vertex )
704                 indices     ( 6 per billboard ( 2 tris ) if not point rendering )
705                 tex. coords ( 2D coords, 1 or 4 per billboard )
706        */
707
708                // Warn if user requested an invalid setup
709                // Do it here so it only appears once
710                if (mPointRendering && mBillboardType != BBT_POINT)
711                {
712
713                        LogManager::getSingleton().logMessage("Warning: BillboardSet " +
714                                mName + " has point rendering enabled but is using a type "
715                                "other than BBT_POINT, this may not give you the results you "
716                                "expect.");
717                }
718
719        mVertexData = new VertexData();
720                if (mPointRendering)
721                        mVertexData->vertexCount = mPoolSize;
722                else
723                        mVertexData->vertexCount = mPoolSize * 4;
724
725        mVertexData->vertexStart = 0;
726
727        // Vertex declaration
728        VertexDeclaration* decl = mVertexData->vertexDeclaration;
729        VertexBufferBinding* binding = mVertexData->vertexBufferBinding;
730
731        size_t offset = 0;
732        decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
733        offset += VertexElement::getTypeSize(VET_FLOAT3);
734        decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
735        offset += VertexElement::getTypeSize(VET_COLOUR);
736        // Texture coords irrelevant when enabled point rendering (generated
737        // in point sprite mode, and unused in standard point mode)
738        if (!mPointRendering)
739        {
740            decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
741        }
742
743        mMainBuf =
744            HardwareBufferManager::getSingleton().createVertexBuffer(
745                decl->getVertexSize(0),
746                mVertexData->vertexCount,
747                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
748        // bind position and diffuses
749        binding->setBinding(0, mMainBuf);
750
751                if (!mPointRendering)
752                {
753                        mIndexData  = new IndexData();
754                        mIndexData->indexStart = 0;
755                        mIndexData->indexCount = mPoolSize * 6;
756
757                        mIndexData->indexBuffer = HardwareBufferManager::getSingleton().
758                                createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
759                                        mIndexData->indexCount,
760                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY);
761
762                        /* Create indexes (will be the same every frame)
763                           Using indexes because it means 1/3 less vertex transforms (4 instead of 6)
764
765                           Billboard layout relative to camera:
766
767                                2-----3
768                                |    /|
769                                |  /  |
770                                |/    |
771                                0-----1
772                        */
773
774                        ushort* pIdx = static_cast<ushort*>(
775                                mIndexData->indexBuffer->lock(0,
776                                  mIndexData->indexBuffer->getSizeInBytes(),
777                                  HardwareBuffer::HBL_DISCARD) );
778
779                        for(
780                                size_t idx, idxOff, bboard = 0;
781                                bboard < mPoolSize;
782                                ++bboard )
783                        {
784                                // Do indexes
785                                idx    = bboard * 6;
786                                idxOff = bboard * 4;
787
788                                pIdx[idx] = static_cast<unsigned short>(idxOff); // + 0;, for clarity
789                                pIdx[idx+1] = static_cast<unsigned short>(idxOff + 1);
790                                pIdx[idx+2] = static_cast<unsigned short>(idxOff + 3);
791                                pIdx[idx+3] = static_cast<unsigned short>(idxOff + 0);
792                                pIdx[idx+4] = static_cast<unsigned short>(idxOff + 3);
793                                pIdx[idx+5] = static_cast<unsigned short>(idxOff + 2);
794
795                        }
796
797                        mIndexData->indexBuffer->unlock();
798                }
799        mBuffersCreated = true;
800    }
801    //-----------------------------------------------------------------------
802        void BillboardSet::_destroyBuffers(void)
803        {
804        if (mVertexData)
805        {
806            delete mVertexData;
807            mVertexData = 0;
808        }
809        if (mIndexData)
810        {
811            delete mIndexData;
812            mIndexData = 0;
813        }
814                mBuffersCreated = false;
815
816        }
817    //-----------------------------------------------------------------------
818    unsigned int BillboardSet::getPoolSize(void) const
819    {
820        return static_cast< unsigned int >( mBillboardPool.size() );
821    }
822
823    //-----------------------------------------------------------------------
824    void BillboardSet::_notifyBillboardResized(void)
825    {
826        mAllDefaultSize = false;
827    }
828
829    //-----------------------------------------------------------------------
830    void BillboardSet::_notifyBillboardRotated(void)
831    {
832        mAllDefaultRotation = false;
833    }
834
835    //-----------------------------------------------------------------------
836    void BillboardSet::getParametricOffsets(
837        Real& left, Real& right, Real& top, Real& bottom )
838    {
839        switch( mOriginType )
840        {
841        case BBO_TOP_LEFT:
842            left = 0.0f;
843            right = 1.0f;
844            top = 0.0f;
845            bottom = 1.0f;
846            break;
847
848        case BBO_TOP_CENTER:
849            left = -0.5f;
850            right = 0.5f;
851            top = 0.0f;
852            bottom = 1.0f;
853            break;
854
855        case BBO_TOP_RIGHT:
856            left = -1.0f;
857            right = 0.0f;
858            top = 0.0f;
859            bottom = 1.0f;
860            break;
861
862        case BBO_CENTER_LEFT:
863            left = 0.0f;
864            right = 1.0f;
865            top = -0.5f;
866            bottom = 0.5f;
867            break;
868
869        case BBO_CENTER:
870            left = -0.5f;
871            right = 0.5f;
872            top = -0.5f;
873            bottom = 0.5f;
874            break;
875
876        case BBO_CENTER_RIGHT:
877            left = -1.0f;
878            right = 0.0f;
879            top = -0.5f;
880            bottom = 0.5f;
881            break;
882
883        case BBO_BOTTOM_LEFT:
884            left = 0.0f;
885            right = 1.0f;
886            top = -1.0f;
887            bottom = 0.0f;
888            break;
889
890        case BBO_BOTTOM_CENTER:
891            left = -0.5f;
892            right = 0.5f;
893            top = -1.0f;
894            bottom = 0.0f;
895            break;
896
897        case BBO_BOTTOM_RIGHT:
898            left = -1.0f;
899            right = 0.0f;
900            top = -1.0f;
901            bottom = 0.0f;
902            break;
903        }
904    }
905    //-----------------------------------------------------------------------
906    bool BillboardSet::getCullIndividually(void) const
907    {
908        return mCullIndividual;
909    }
910    //-----------------------------------------------------------------------
911    void BillboardSet::setCullIndividually(bool cullIndividual)
912    {
913        mCullIndividual = cullIndividual;
914    }
915    //-----------------------------------------------------------------------
916    bool BillboardSet::billboardVisible(Camera* cam, const Billboard& bill)
917    {
918        // Return always visible if not culling individually
919        if (!mCullIndividual) return true;
920
921        // Cull based on sphere (have to transform less)
922        Sphere sph;
923        Matrix4 xworld;
924
925        getWorldTransforms(&xworld);
926
927        sph.setCenter(xworld * bill.mPosition);
928
929        if (bill.mOwnDimensions)
930        {
931            sph.setRadius(std::max(bill.mWidth, bill.mHeight));
932        }
933        else
934        {
935            sph.setRadius(std::max(mDefaultWidth, mDefaultHeight));
936        }
937
938        return cam->isVisible(sph);
939
940    }
941    //-----------------------------------------------------------------------
942    void BillboardSet::increasePool(unsigned int size)
943    {
944        size_t oldSize = mBillboardPool.size();
945
946        // Increase size
947        mBillboardPool.reserve(size);
948        mBillboardPool.resize(size);
949
950        // Create new billboards
951        for( size_t i = oldSize; i < size; ++i )
952            mBillboardPool[i] = new Billboard();
953
954    }
955    //-----------------------------------------------------------------------
956    void BillboardSet::genBillboardAxes(Vector3* pX, Vector3 *pY, const Billboard* bb)
957    {
958        // If we're using accurate facing, recalculate camera direction per BB
959        if (mAccurateFacing &&
960            (mBillboardType == BBT_POINT ||
961            mBillboardType == BBT_ORIENTED_COMMON ||
962            mBillboardType == BBT_ORIENTED_SELF))
963        {
964            // cam -> bb direction
965            mCamDir = bb->mPosition - mCamPos;
966            mCamDir.normalise();
967        }
968
969
970        switch (mBillboardType)
971        {
972        case BBT_POINT:
973            if (mAccurateFacing)
974            {
975                // Point billboards will have 'up' based on but not equal to cameras
976                // Use pY temporarily to avoid allocation
977                *pY = mCamQ * Vector3::UNIT_Y;
978                *pX = mCamDir.crossProduct(*pY);
979                pX->normalise();
980                *pY = pX->crossProduct(mCamDir); // both normalised already
981            }
982            else
983            {
984                // Get camera axes for X and Y (depth is irrelevant)
985                *pX = mCamQ * Vector3::UNIT_X;
986                *pY = mCamQ * Vector3::UNIT_Y;
987            }
988            break;
989
990        case BBT_ORIENTED_COMMON:
991            // Y-axis is common direction
992            // X-axis is cross with camera direction
993            *pY = mCommonDirection;
994            *pX = mCamDir.crossProduct(*pY);
995            pX->normalise();
996            break;
997
998        case BBT_ORIENTED_SELF:
999            // Y-axis is direction
1000            // X-axis is cross with camera direction
1001            // Scale direction first
1002            *pY = bb->mDirection;
1003            *pX = mCamDir.crossProduct(*pY);
1004            pX->normalise();
1005            break;
1006
1007        case BBT_PERPENDICULAR_COMMON:
1008            // X-axis is up-vector cross common direction
1009            // Y-axis is common direction cross X-axis
1010            *pX = mCommonUpVector.crossProduct(mCommonDirection);
1011            *pY = mCommonDirection.crossProduct(*pX);
1012            break;
1013
1014        case BBT_PERPENDICULAR_SELF:
1015            // X-axis is up-vector cross own direction
1016            // Y-axis is own direction cross X-axis
1017            *pX = mCommonUpVector.crossProduct(bb->mDirection);
1018            pX->normalise();
1019            *pY = bb->mDirection.crossProduct(*pX); // both should be normalised
1020            break;
1021        }
1022
1023    }
1024    //-----------------------------------------------------------------------
1025    void BillboardSet::setBillboardType(BillboardType bbt)
1026    {
1027        mBillboardType = bbt;
1028    }
1029    //-----------------------------------------------------------------------
1030    BillboardType BillboardSet::getBillboardType(void) const
1031    {
1032        return mBillboardType;
1033    }
1034    //-----------------------------------------------------------------------
1035    void BillboardSet::setCommonDirection(const Vector3& vec)
1036    {
1037        mCommonDirection = vec;
1038    }
1039    //-----------------------------------------------------------------------
1040    const Vector3& BillboardSet::getCommonDirection(void) const
1041    {
1042        return mCommonDirection;
1043    }
1044    //-----------------------------------------------------------------------
1045    void BillboardSet::setCommonUpVector(const Vector3& vec)
1046    {
1047        mCommonUpVector = vec;
1048    }
1049    //-----------------------------------------------------------------------
1050    const Vector3& BillboardSet::getCommonUpVector(void) const
1051    {
1052        return mCommonUpVector;
1053    }
1054        //-----------------------------------------------------------------------
1055        uint32 BillboardSet::getTypeFlags(void) const
1056        {
1057                return SceneManager::FX_TYPE_MASK;
1058        }
1059    //-----------------------------------------------------------------------
1060    void BillboardSet::genVertices(
1061        const Vector3* const offsets, const Billboard& bb)
1062    {
1063        RGBA colour;
1064        Root::getSingleton().convertColourValue(bb.mColour, &colour);
1065                RGBA* pCol;
1066
1067        // Texcoords
1068        assert( bb.mUseTexcoordRect || bb.mTexcoordIndex < mTextureCoords.size() );
1069        const Ogre::FloatRect & r =
1070            bb.mUseTexcoordRect ? bb.mTexcoordRect : mTextureCoords[bb.mTexcoordIndex];
1071
1072                if (mPointRendering)
1073                {
1074                        // Single vertex per billboard, ignore offsets
1075                        // position
1076            *mLockPtr++ = bb.mPosition.x;
1077            *mLockPtr++ = bb.mPosition.y;
1078            *mLockPtr++ = bb.mPosition.z;
1079            // Colour
1080            // Convert float* to RGBA*
1081            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1082            *pCol++ = colour;
1083                        // Update lock pointer
1084                        mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1085            // No texture coords in point rendering
1086                }
1087                else if (mAllDefaultRotation || bb.mRotation == Radian(0))
1088        {
1089            // Left-top
1090            // Positions
1091            *mLockPtr++ = offsets[0].x + bb.mPosition.x;
1092            *mLockPtr++ = offsets[0].y + bb.mPosition.y;
1093            *mLockPtr++ = offsets[0].z + bb.mPosition.z;
1094            // Colour
1095            // Convert float* to RGBA*
1096            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1097            *pCol++ = colour;
1098            // Update lock pointer
1099            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1100            // Texture coords
1101            *mLockPtr++ = r.left;
1102            *mLockPtr++ = r.bottom;
1103
1104            // Right-top
1105            // Positions
1106            *mLockPtr++ = offsets[1].x + bb.mPosition.x;
1107            *mLockPtr++ = offsets[1].y + bb.mPosition.y;
1108            *mLockPtr++ = offsets[1].z + bb.mPosition.z;
1109            // Colour
1110            // Convert float* to RGBA*
1111            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1112            *pCol++ = colour;
1113            // Update lock pointer
1114            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1115            // Texture coords
1116            *mLockPtr++ = r.right;
1117            *mLockPtr++ = r.bottom;
1118
1119            // Left-bottom
1120            // Positions
1121            *mLockPtr++ = offsets[2].x + bb.mPosition.x;
1122            *mLockPtr++ = offsets[2].y + bb.mPosition.y;
1123            *mLockPtr++ = offsets[2].z + bb.mPosition.z;
1124            // Colour
1125            // Convert float* to RGBA*
1126            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1127            *pCol++ = colour;
1128            // Update lock pointer
1129            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1130            // Texture coords
1131            *mLockPtr++ = r.left;
1132            *mLockPtr++ = r.top;
1133
1134            // Right-bottom
1135            // Positions
1136            *mLockPtr++ = offsets[3].x + bb.mPosition.x;
1137            *mLockPtr++ = offsets[3].y + bb.mPosition.y;
1138            *mLockPtr++ = offsets[3].z + bb.mPosition.z;
1139            // Colour
1140            // Convert float* to RGBA*
1141            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1142            *pCol++ = colour;
1143            // Update lock pointer
1144            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1145            // Texture coords
1146            *mLockPtr++ = r.right;
1147            *mLockPtr++ = r.top;
1148        }
1149        else if (mRotationType == BBR_VERTEX)
1150        {
1151            // TODO: Cache axis when billboard type is BBT_POINT or BBT_PERPENDICULAR_COMMON
1152            Vector3 axis = (offsets[3] - offsets[0]).crossProduct(offsets[2] - offsets[1]).normalisedCopy();
1153
1154            Quaternion rotation(bb.mRotation, axis);
1155            Vector3 pt;
1156
1157            // Left-top
1158            // Positions
1159            pt = rotation * offsets[0];
1160            *mLockPtr++ = pt.x + bb.mPosition.x;
1161            *mLockPtr++ = pt.y + bb.mPosition.y;
1162            *mLockPtr++ = pt.z + bb.mPosition.z;
1163            // Colour
1164            // Convert float* to RGBA*
1165            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1166            *pCol++ = colour;
1167            // Update lock pointer
1168            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1169            // Texture coords
1170            *mLockPtr++ = r.left;
1171            *mLockPtr++ = r.bottom;
1172
1173            // Right-top
1174            // Positions
1175            pt = rotation * offsets[1];
1176            *mLockPtr++ = pt.x + bb.mPosition.x;
1177            *mLockPtr++ = pt.y + bb.mPosition.y;
1178            *mLockPtr++ = pt.z + bb.mPosition.z;
1179            // Colour
1180            // Convert float* to RGBA*
1181            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1182            *pCol++ = colour;
1183            // Update lock pointer
1184            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1185            // Texture coords
1186            *mLockPtr++ = r.right;
1187            *mLockPtr++ = r.bottom;
1188
1189            // Left-bottom
1190            // Positions
1191            pt = rotation * offsets[2];
1192            *mLockPtr++ = pt.x + bb.mPosition.x;
1193            *mLockPtr++ = pt.y + bb.mPosition.y;
1194            *mLockPtr++ = pt.z + bb.mPosition.z;
1195            // Colour
1196            // Convert float* to RGBA*
1197            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1198            *pCol++ = colour;
1199            // Update lock pointer
1200            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1201            // Texture coords
1202            *mLockPtr++ = r.left;
1203            *mLockPtr++ = r.top;
1204
1205            // Right-bottom
1206            // Positions
1207            pt = rotation * offsets[3];
1208            *mLockPtr++ = pt.x + bb.mPosition.x;
1209            *mLockPtr++ = pt.y + bb.mPosition.y;
1210            *mLockPtr++ = pt.z + bb.mPosition.z;
1211            // Colour
1212            // Convert float* to RGBA*
1213            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1214            *pCol++ = colour;
1215            // Update lock pointer
1216            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1217            // Texture coords
1218            *mLockPtr++ = r.right;
1219            *mLockPtr++ = r.top;
1220        }
1221        else
1222        {
1223            const Real      cos_rot  ( Math::Cos(bb.mRotation)   );
1224            const Real      sin_rot  ( Math::Sin(bb.mRotation)   );
1225
1226            float width = (r.right-r.left)/2;
1227            float height = (r.top-r.bottom)/2;
1228            float mid_u = r.left+width;
1229            float mid_v = r.bottom+height;
1230
1231            float cos_rot_w = cos_rot * width;
1232            float cos_rot_h = cos_rot * height;
1233            float sin_rot_w = sin_rot * width;
1234            float sin_rot_h = sin_rot * height;
1235
1236            // Left-top
1237            // Positions
1238            *mLockPtr++ = offsets[0].x + bb.mPosition.x;
1239            *mLockPtr++ = offsets[0].y + bb.mPosition.y;
1240            *mLockPtr++ = offsets[0].z + bb.mPosition.z;
1241            // Colour
1242            // Convert float* to RGBA*
1243            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1244            *pCol++ = colour;
1245            // Update lock pointer
1246            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1247            // Texture coords
1248            *mLockPtr++ = mid_u - cos_rot_w + sin_rot_h;
1249            *mLockPtr++ = mid_v - sin_rot_w - cos_rot_h;
1250
1251            // Right-top
1252            // Positions
1253            *mLockPtr++ = offsets[1].x + bb.mPosition.x;
1254            *mLockPtr++ = offsets[1].y + bb.mPosition.y;
1255            *mLockPtr++ = offsets[1].z + bb.mPosition.z;
1256            // Colour
1257            // Convert float* to RGBA*
1258            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1259            *pCol++ = colour;
1260            // Update lock pointer
1261            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1262            // Texture coords
1263            *mLockPtr++ = mid_u + cos_rot_w + sin_rot_h;
1264            *mLockPtr++ = mid_v + sin_rot_w - cos_rot_h;
1265
1266            // Left-bottom
1267            // Positions
1268            *mLockPtr++ = offsets[2].x + bb.mPosition.x;
1269            *mLockPtr++ = offsets[2].y + bb.mPosition.y;
1270            *mLockPtr++ = offsets[2].z + bb.mPosition.z;
1271            // Colour
1272            // Convert float* to RGBA*
1273            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1274            *pCol++ = colour;
1275            // Update lock pointer
1276            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1277            // Texture coords
1278            *mLockPtr++ = mid_u - cos_rot_w - sin_rot_h;
1279            *mLockPtr++ = mid_v - sin_rot_w + cos_rot_h;
1280
1281            // Right-bottom
1282            // Positions
1283            *mLockPtr++ = offsets[3].x + bb.mPosition.x;
1284            *mLockPtr++ = offsets[3].y + bb.mPosition.y;
1285            *mLockPtr++ = offsets[3].z + bb.mPosition.z;
1286            // Colour
1287            // Convert float* to RGBA*
1288            pCol = static_cast<RGBA*>(static_cast<void*>(mLockPtr));
1289            *pCol++ = colour;
1290            // Update lock pointer
1291            mLockPtr = static_cast<float*>(static_cast<void*>(pCol));
1292            // Texture coords
1293            *mLockPtr++ = mid_u + cos_rot_w - sin_rot_h;
1294            *mLockPtr++ = mid_v + sin_rot_w + cos_rot_h;
1295        }
1296
1297    }
1298    //-----------------------------------------------------------------------
1299    void BillboardSet::genVertOffsets(Real inleft, Real inright, Real intop, Real inbottom,
1300        Real width, Real height, const Vector3& x, const Vector3& y, Vector3* pDestVec)
1301    {
1302        Vector3 vLeftOff, vRightOff, vTopOff, vBottomOff;
1303        /* Calculate default offsets. Scale the axes by
1304           parametric offset and dimensions, ready to be added to
1305           positions.
1306        */
1307
1308        vLeftOff   = x * ( inleft   * width );
1309        vRightOff  = x * ( inright  * width );
1310        vTopOff    = y * ( intop   * height );
1311        vBottomOff = y * ( inbottom * height );
1312
1313        // Make final offsets to vertex positions
1314        pDestVec[0] = vLeftOff  + vTopOff;
1315        pDestVec[1] = vRightOff + vTopOff;
1316        pDestVec[2] = vLeftOff  + vBottomOff;
1317        pDestVec[3] = vRightOff + vBottomOff;
1318
1319    }
1320    //-----------------------------------------------------------------------
1321    const String& BillboardSet::getMovableType(void) const
1322    {
1323                return BillboardSetFactory::FACTORY_TYPE_NAME;
1324    }
1325    //-----------------------------------------------------------------------
1326    Real BillboardSet::getSquaredViewDepth(const Camera* const cam) const
1327    {
1328        assert(mParentNode);
1329        return mParentNode->getSquaredViewDepth(cam);
1330    }
1331    //-----------------------------------------------------------------------
1332        Real BillboardSet::getBoundingRadius(void) const
1333        {
1334                return mBoundingRadius;
1335        }
1336    //-----------------------------------------------------------------------
1337    const LightList& BillboardSet::getLights(void) const
1338    {
1339        // It's actually quite unlikely that this will be called,
1340        // because most billboards are unlit, but here we go anyway
1341        return getParentSceneNode()->findLights(this->getBoundingRadius());
1342    }
1343
1344    void BillboardSet::setTextureCoords( Ogre::FloatRect const * coords, uint16 numCoords )
1345    {
1346      if( !numCoords || !coords ) {
1347        setTextureStacksAndSlices( 1, 1 );
1348      }
1349      //  clear out any previous allocation (as vectors may not shrink)
1350      TextureCoordSets().swap( mTextureCoords );
1351      //  make room
1352      mTextureCoords.resize( numCoords );
1353      //  copy in data
1354      std::copy( coords, coords+numCoords, &mTextureCoords.front() );
1355    }
1356
1357    void BillboardSet::setTextureStacksAndSlices( uchar stacks, uchar slices )
1358    {
1359      if( stacks == 0 ) stacks = 1;
1360      if( slices == 0 ) slices = 1;
1361      //  clear out any previous allocation (as vectors may not shrink)
1362      TextureCoordSets().swap( mTextureCoords );
1363      //  make room
1364      mTextureCoords.resize( (size_t)stacks * slices );
1365      unsigned int coordIndex = 0;
1366      //  spread the U and V coordinates across the rects
1367      for( uint v = 0; v < stacks; ++v ) {
1368        //  (float)X / X is guaranteed to be == 1.0f for X up to 8 million, so
1369        //  our range of 1..256 is quite enough to guarantee perfect coverage.
1370        float top = (float)v / (float)stacks;
1371        float bottom = ((float)v + 1) / (float)stacks;
1372        for( uint u = 0; u < slices; ++u ) {
1373          Ogre::FloatRect & r = mTextureCoords[coordIndex];
1374          r.left = (float)u / (float)slices;
1375          r.bottom = bottom;
1376          r.right = ((float)u + 1) / (float)slices;
1377          r.top = top;
1378          ++coordIndex;
1379        }
1380      }
1381      assert( coordIndex == (size_t)stacks * slices );
1382    }
1383        //-----------------------------------------------------------------------
1384    Ogre::FloatRect const * BillboardSet::getTextureCoords( uint16 * oNumCoords )
1385    {
1386      *oNumCoords = (uint16)mTextureCoords.size();
1387      //  std::vector<> is guaranteed to be contiguous
1388      return &mTextureCoords.front();
1389    }
1390        //-----------------------------------------------------------------------
1391        void BillboardSet::setPointRenderingEnabled(bool enabled)
1392        {
1393                if (enabled != mPointRendering)
1394                {
1395                        mPointRendering = enabled;
1396                        // Different buffer structure (1 or 4 verts per billboard)
1397                        _destroyBuffers();
1398                }
1399        }
1400        //-----------------------------------------------------------------------
1401        //-----------------------------------------------------------------------
1402        String BillboardSetFactory::FACTORY_TYPE_NAME = "BillboardSet";
1403        //-----------------------------------------------------------------------
1404        const String& BillboardSetFactory::getType(void) const
1405        {
1406                return FACTORY_TYPE_NAME;
1407        }
1408        //-----------------------------------------------------------------------
1409        MovableObject* BillboardSetFactory::createInstanceImpl( const String& name,
1410                const NameValuePairList* params)
1411        {
1412                // may have parameters
1413                bool externalData = false;
1414                unsigned int poolSize = 0;
1415
1416                if (params != 0)
1417                {
1418                        NameValuePairList::const_iterator ni = params->find("poolSize");
1419                        if (ni != params->end())
1420                        {
1421                                poolSize = StringConverter::parseUnsignedInt(ni->second);
1422                        }
1423                        ni = params->find("externalData");
1424                        if (ni != params->end())
1425                        {
1426                                externalData = StringConverter::parseBool(ni->second);
1427                        }
1428
1429                }
1430
1431                if (poolSize > 0)
1432                {
1433                        return new BillboardSet(name, poolSize, externalData);
1434                }
1435                else
1436                {
1437                        return new BillboardSet(name);
1438                }
1439
1440        }
1441        //-----------------------------------------------------------------------
1442        void BillboardSetFactory::destroyInstance( MovableObject* obj)
1443        {
1444                delete obj;
1445        }
1446
1447
1448}
Note: See TracBrowser for help on using the repository browser.