Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/OgreMain/src/OgreBillboardSet.cpp @ 29

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

=hoffentlich gehts jetzt

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