Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreBillboardSet.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgreBillboardSet.h"
00028 
00029 #include "OgreBillboard.h"
00030 #include "OgreMaterialManager.h"
00031 #include "OgreHardwareBufferManager.h"
00032 #include "OgreCamera.h"
00033 #include "OgreMath.h"
00034 #include "OgreSphere.h"
00035 #include "OgreRoot.h"
00036 #include "OgreException.h"
00037 #include <algorithm>
00038 
00039 namespace Ogre {
00040     #define POSITION_BINDING 0
00041     #define COLOUR_BINDING 1
00042     #define TEXCOORD_BINDING 2
00043 
00044     String BillboardSet::msMovableType = "BillboardSet";
00045     //-----------------------------------------------------------------------
00046     BillboardSet::BillboardSet() :
00047         mOriginType( BBO_CENTER ),
00048         mAllDefaultSize( true ),
00049         mAutoExtendPool( true ),
00050         mFixedTextureCoords(true),
00051         mVertexData(0),
00052         mIndexData(0),
00053         mCullIndividual( false ),
00054         mBillboardType(BBT_POINT)
00055     {
00056         setDefaultDimensions( 100, 100 );
00057         setMaterialName( "BaseWhite" );
00058     }
00059 
00060     //-----------------------------------------------------------------------
00061     BillboardSet::BillboardSet(
00062         const String& name,
00063         unsigned int poolSize ) :
00064         mName( name ),
00065         mOriginType( BBO_CENTER ),
00066         mAllDefaultSize( true ),
00067         mAutoExtendPool( true ),
00068         mFixedTextureCoords(true),
00069         mVertexData(0),
00070         mIndexData(0),
00071         mCullIndividual( false ),
00072         mBillboardType(BBT_POINT)
00073     {
00074         setDefaultDimensions( 100, 100 );
00075         setMaterialName( "BaseWhite" );
00076         setPoolSize( poolSize );
00077     }
00078     //-----------------------------------------------------------------------
00079     BillboardSet::~BillboardSet()
00080     {
00081         // Free pool items
00082         BillboardPool::iterator i;
00083         for (i = mBillboardPool.begin(); i != mBillboardPool.end(); ++i)
00084         {
00085             delete *i;
00086         }
00087 
00088         // Delete shared buffers
00089         if(mVertexData)
00090             delete mVertexData;
00091         if(mIndexData)
00092             delete mIndexData;
00093     }
00094     //-----------------------------------------------------------------------
00095     Billboard* BillboardSet::createBillboard(
00096         const Vector3& position,
00097         const ColourValue& colour )
00098     {
00099         if( mFreeBillboards.empty() )
00100         {
00101             if( mAutoExtendPool )
00102             {
00103                 setPoolSize( getPoolSize() * 2 );
00104             }
00105             else
00106             {
00107                 return 0;
00108             }
00109         }
00110 
00111         // Get a new billboard
00112         Billboard* newBill = mFreeBillboards.front();
00113         mFreeBillboards.pop_front();
00114         mActiveBillboards.push_back(newBill);
00115 
00116         newBill->setPosition(position);
00117         newBill->setColour(colour);
00118         newBill->_notifyOwner(this);
00119 
00120         _updateBounds();
00121 
00122         return newBill;
00123     }
00124 
00125     //-----------------------------------------------------------------------
00126     Billboard* BillboardSet::createBillboard(
00127         Real x, Real y, Real z,
00128         const ColourValue& colour )
00129     {
00130         return createBillboard( Vector3( x, y, z ), colour );
00131     }
00132 
00133     //-----------------------------------------------------------------------
00134     int BillboardSet::getNumBillboards(void) const
00135     {
00136         return static_cast< int >( mActiveBillboards.size() );
00137     }
00138 
00139     //-----------------------------------------------------------------------
00140     void BillboardSet::clear()
00141     {
00142         // Remove all active instances
00143         mActiveBillboards.clear();
00144     }
00145 
00146     //-----------------------------------------------------------------------
00147     Billboard* BillboardSet::getBillboard( unsigned int index ) const
00148     {
00149         assert(
00150             index < mActiveBillboards.size() &&
00151             "Billboard index out of bounds." );
00152 
00153         /* We can't access it directly, so we check wether it's in the first
00154            or the second half, then we start either from the beginning or the
00155            end of the list
00156         */
00157         ActiveBillboardList::const_iterator it;
00158         if( index >= ( mActiveBillboards.size() >> 1 ) )
00159         {
00160             index = static_cast<unsigned int>(mActiveBillboards.size()) - index;
00161             for( it = mActiveBillboards.end(); index; --index, --it );
00162         }
00163         else
00164         {
00165             for( it = mActiveBillboards.begin(); index; --index, ++it );
00166         }
00167 
00168         return *it;
00169     }
00170 
00171     //-----------------------------------------------------------------------
00172     void BillboardSet::removeBillboard(unsigned int index)
00173     {
00174         assert(
00175             index < mActiveBillboards.size() &&
00176             "Billboard index out of bounds." );
00177 
00178         /* We can't access it directly, so we check wether it's in the first
00179            or the second half, then we start either from the beginning or the
00180            end of the list.
00181            We then remove the billboard form the 'used' list and add it to
00182            the 'free' list.
00183         */
00184         ActiveBillboardList::iterator it;
00185         if( index >= ( mActiveBillboards.size() >> 1 ) )
00186         {
00187             index = static_cast<unsigned int>(mActiveBillboards.size()) - index;
00188             for( it = mActiveBillboards.end(); index; --index, --it );
00189         }
00190         else
00191         {
00192             for( it = mActiveBillboards.begin(); index; --index, ++it );
00193         }
00194 
00195         mFreeBillboards.push_back( *it );
00196         mActiveBillboards.erase( it );
00197     }
00198 
00199     //-----------------------------------------------------------------------
00200     void BillboardSet::removeBillboard( Billboard* pBill )
00201     {
00202         mActiveBillboards.remove( pBill );
00203         mFreeBillboards.push_back( pBill );
00204     }
00205 
00206     //-----------------------------------------------------------------------
00207     void BillboardSet::setBillboardOrigin( BillboardOrigin origin )
00208     {
00209         mOriginType = origin;
00210     }
00211 
00212     //-----------------------------------------------------------------------
00213     BillboardOrigin BillboardSet::getBillboardOrigin(void) const
00214     {
00215         return mOriginType;
00216     }
00217 
00218     //-----------------------------------------------------------------------
00219     void BillboardSet::setDefaultDimensions( Real width, Real height )
00220     {
00221         mDefaultWidth = width;
00222         mDefaultHeight = height;
00223     }
00224     //-----------------------------------------------------------------------
00225     void BillboardSet::setDefaultWidth(Real width)
00226     {
00227         mDefaultWidth = width;
00228     }
00229     //-----------------------------------------------------------------------
00230     Real BillboardSet::getDefaultWidth(void) const
00231     {
00232         return mDefaultWidth;
00233     }
00234     //-----------------------------------------------------------------------
00235     void BillboardSet::setDefaultHeight(Real height)
00236     {
00237         mDefaultHeight = height;
00238     }
00239     //-----------------------------------------------------------------------
00240     Real BillboardSet::getDefaultHeight(void) const
00241     {
00242         return mDefaultHeight;
00243     }
00244     //-----------------------------------------------------------------------
00245     void BillboardSet::setMaterialName( const String& name )
00246     {
00247         mMaterialName = name;
00248 
00249         mpMaterial = static_cast<Material *>(
00250             MaterialManager::getSingleton().getByName(name) );
00251 
00252         if (!mpMaterial)
00253             Except( Exception::ERR_ITEM_NOT_FOUND, "Could not find material " + name,
00254                 "BillboardSet::setMaterialName" );
00255 
00256         /* Ensure that the new material was loaded (will not load again if
00257            already loaded anyway)
00258         */
00259         mpMaterial->load();
00260     }
00261 
00262     //-----------------------------------------------------------------------
00263     const String& BillboardSet::getMaterialName(void) const
00264     {
00265         return mMaterialName;
00266     }
00267 
00268     //-----------------------------------------------------------------------
00269     void BillboardSet::_notifyCurrentCamera( Camera* cam )
00270     {
00271         /* Generate the vertices for all the billboards relative to the camera
00272            Also take the opportunity to update the vertex colours
00273            May as well do it here to save on loops elsewhere
00274         */
00275 
00276         /* NOTE: most engines generate world coordinates for the billboards
00277            directly, taking the world axes of the camera as offsets to the 
00278            center points. I take a different approach, reverse-transforming 
00279            the camera world axes into local billboard space. 
00280            Why?
00281            Well, it's actually more efficient this way, because I only have to
00282            reverse-transform using the billboardset world matrix (inverse) 
00283            once, from then on it's simple additions (assuming identically 
00284            sized billboards). If I transformed every billboard center by it's 
00285            world transform, that's a matrix multiplication per billboard 
00286            instead.
00287            I leave the final transform to the render pipeline since that can 
00288            use hardware TnL if it is available.
00289         */
00290 
00291         /*
00292         // Min and max bounds for AABB
00293         Vector3 min( Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY );
00294         Vector3 max( Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY );
00295         */
00296 
00297         ActiveBillboardList::iterator it;
00298         // Parametric offsets of origin
00299         Real leftOff, rightOff, topOff, bottomOff;
00300 
00301         // Boundary offsets based on origin and camera orientation
00302         // Vector3 vLeftOff, vRightOff, vTopOff, vBottomOff;
00303         // Final vertex offsets, used where sizes all default to save calcs
00304         Vector3 vOffset[4];
00305 
00306         // Get offsets for origin type
00307         getParametricOffsets(leftOff, rightOff, topOff, bottomOff);
00308         // Get camera axes in billboard space
00309         Vector3 camX, camY;
00310 
00311         // Generate axes etc up-front if not oriented per-billboard
00312         if (mBillboardType != BBT_ORIENTED_SELF)
00313         {
00314             genBillboardAxes(*cam, &camX, &camY);
00315 
00316             /* If all billboards are the same size we can precalculate the
00317                offsets and just use '+' instead of '*' for each billboard,
00318                and it should be faster.
00319             */
00320             genVertOffsets(leftOff, rightOff, topOff, bottomOff, 
00321                 mDefaultWidth, mDefaultHeight, camX, camY, vOffset);
00322 
00323         }
00324 
00325         // Init num visible
00326         mNumVisibleBillboards = 0;
00327 
00328         HardwareVertexBufferSharedPtr vPosBuf = 
00329             mVertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
00330 
00331         Real* pV = static_cast<Real*>( 
00332             vPosBuf->lock(HardwareBuffer::HBL_DISCARD) );
00333 
00334         HardwareVertexBufferSharedPtr vColBuf = 
00335             mVertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
00336 
00337         RGBA* pC = static_cast<RGBA*>( 
00338             vColBuf->lock(HardwareBuffer::HBL_DISCARD) );
00339 
00340         HardwareVertexBufferSharedPtr vTexBuf = 
00341             mVertexData->vertexBufferBinding->getBuffer(TEXCOORD_BINDING);
00342 
00343         Real* pT = 0;
00344         if (!mFixedTextureCoords)
00345         {
00346             pT = static_cast<Real*>( 
00347                 vTexBuf->lock(HardwareBuffer::HBL_DISCARD) );
00348         }
00349 
00350         if( mAllDefaultSize ) // If they're all the same size
00351         {
00352             /* No per-billboard checking, just blast through.
00353                Saves us an if clause every billboard which may
00354                make a difference.
00355             */
00356 
00357             if (mBillboardType == BBT_ORIENTED_SELF)
00358             {
00359                 for( it = mActiveBillboards.begin();
00360                     it != mActiveBillboards.end();
00361                     ++it )
00362                 {
00363                     // Skip if not visible (NB always true if not bounds checking individual billboards)
00364                     if (!billboardVisible(cam, it)) continue;
00365 
00366                     // Have to generate axes & offsets per billboard
00367                     genBillboardAxes(*cam, &camX, &camY, *it);
00368                     genVertOffsets(leftOff, rightOff, topOff, bottomOff, 
00369                         mDefaultWidth, mDefaultHeight, camX, camY, vOffset);
00370 
00371                     genVertices(&pV, &pC, &pT, vOffset, *it);
00372 
00373                     // Increment visibles
00374                     mNumVisibleBillboards++;
00375                 }
00376             } else
00377             {
00378                 for( it = mActiveBillboards.begin();
00379                     it != mActiveBillboards.end();
00380                     ++it )
00381                 {
00382                     // Skip if not visible (NB always true if not bounds checking individual billboards)
00383                     if (!billboardVisible(cam, it)) continue;
00384 
00385                     genVertices(&pV, &pC, &pT, vOffset, *it);
00386 
00387                     // Increment visibles
00388                     mNumVisibleBillboards++;
00389                 }
00390             }
00391         }
00392         else // not all default size
00393         {
00394             Vector3 vOwnOffset[4];
00395             if (mBillboardType == BBT_ORIENTED_SELF)
00396             {
00397                 for( it = mActiveBillboards.begin(); it != mActiveBillboards.end(); ++it )
00398                 {
00399                     // Skip if not visible (NB always true if not bounds checking individual billboards)
00400                     if (!billboardVisible(cam, it)) continue;
00401 
00402                     // Have to generate axes & offsets per billboard
00403                     genBillboardAxes(*cam, &camX, &camY, *it);
00404             
00405                     // If it has own dimensions, or self-oriented, gen offsets
00406                     if( (*it)->mOwnDimensions) 
00407                     {
00408                         // Generate using own dimensions
00409                         genVertOffsets(leftOff, rightOff, topOff, bottomOff, 
00410                             (*it)->mWidth, (*it)->mHeight, camX, camY, vOwnOffset);
00411                         // Create vertex data            
00412                         genVertices(&pV, &pC, &pT, vOwnOffset, *it);
00413                     }
00414                     else // Use default dimension, already computed before the loop, for faster creation
00415                     {
00416                         genVertices(&pV, &pC, &pT, vOffset, *it);
00417                     }
00418 
00419                     // Increment visibles
00420                     mNumVisibleBillboards++;
00421 
00422                 }
00423             } else
00424             {
00425                 for( it = mActiveBillboards.begin(); it != mActiveBillboards.end(); ++it )
00426                 {
00427                     // Skip if not visible (NB always true if not bounds checking individual billboards)
00428                     if (!billboardVisible(cam, it)) continue;
00429 
00430                     // If it has own dimensions, or self-oriented, gen offsets
00431                     if( (*it)->mOwnDimensions) 
00432                     {
00433                         // Generate using own dimensions
00434                         genVertOffsets(leftOff, rightOff, topOff, bottomOff, 
00435                             (*it)->mWidth, (*it)->mHeight, camX, camY, vOwnOffset);
00436                         // Create vertex data            
00437                         genVertices(&pV, &pC, &pT, vOwnOffset, *it);
00438                     }
00439                     else // Use default dimension, already computed before the loop, for faster creation
00440                     {
00441                         genVertices(&pV, &pC, &pT, vOffset, *it);
00442                     }
00443 
00444                     // Increment visibles
00445                     mNumVisibleBillboards++;
00446 
00447                 }
00448             }
00449         }
00450 
00451         if (!mFixedTextureCoords)
00452             vTexBuf->unlock();
00453         vColBuf->unlock();
00454         vPosBuf->unlock();
00455 
00456         /*
00457         // Update bounding box limits
00458         unsigned int vertBufferSize = mNumVisibleBillboards * 4 * 3;
00459 
00460         for( j = 0; j < vertBufferSize; j += 3 )
00461         {
00462                 min.makeFloor( Vector3(
00463                                    mpPositions[j],
00464                                    mpPositions[j+1],
00465                                    mpPositions[j+2] ) );
00466 
00467                 max.makeCeil( Vector3(
00468                                    mpPositions[j],
00469                                    mpPositions[j+1],
00470                                    mpPositions[j+2] ) );
00471         }
00472 
00473         // Set AABB
00474         mAABB.setExtents(min, max);
00475         */
00476     }
00477     //-----------------------------------------------------------------------
00478     void BillboardSet::_updateBounds(void)
00479     {
00480         if (mActiveBillboards.empty())
00481         {
00482             // No billboards, null bbox
00483             mAABB.setNull();
00484             mBoundingRadius = 0.0f;
00485         }
00486         else
00487         {
00488             Real maxSqLen = -1.0f;
00489         
00490             Vector3 min(Math::POS_INFINITY, Math::POS_INFINITY, Math::POS_INFINITY);
00491             Vector3 max(Math::NEG_INFINITY, Math::NEG_INFINITY, Math::NEG_INFINITY);
00492             ActiveBillboardList::iterator i, iend;
00493 
00494             iend = mActiveBillboards.end();
00495             for (i = mActiveBillboards.begin(); i != iend; ++i)
00496             {
00497                 const Vector3& pos = (*i)->getPosition();
00498                 min.makeFloor(pos);
00499                 max.makeCeil(pos);
00500 
00501                 maxSqLen = std::max(maxSqLen, pos.squaredLength());
00502             }
00503             // Adjust for billboard size
00504             Real adjust = std::max(mDefaultWidth, mDefaultHeight);
00505             Vector3 vecAdjust(adjust, adjust, adjust);
00506             min -= vecAdjust;
00507             max += vecAdjust;
00508 
00509             mAABB.setExtents(min, max);
00510             mBoundingRadius = Math::Sqrt(maxSqLen);
00511             
00512         }
00513 
00514         if (mParentNode)
00515             mParentNode->needUpdate();
00516         
00517     }
00518     //-----------------------------------------------------------------------
00519     const AxisAlignedBox& BillboardSet::getBoundingBox(void) const
00520     {
00521         return mAABB;
00522     }
00523 
00524     //-----------------------------------------------------------------------    
00525     void BillboardSet::_updateRenderQueue(RenderQueue* queue)
00526     {
00527         queue->addRenderable(this, mRenderQueueID, RENDERABLE_DEFAULT_PRIORITY);
00528     }
00529 
00530     //-----------------------------------------------------------------------
00531     Material* BillboardSet::getMaterial(void) const
00532     {
00533         return mpMaterial;
00534     }
00535 
00536     //-----------------------------------------------------------------------
00537     void BillboardSet::getRenderOperation(RenderOperation& op)
00538     {
00539         op.operationType = RenderOperation::OT_TRIANGLE_LIST;
00540         op.useIndexes = true;
00541 
00542         op.vertexData = mVertexData;
00543         op.vertexData->vertexCount = mNumVisibleBillboards * 4;
00544         op.vertexData->vertexStart = 0;
00545 
00546         op.indexData = mIndexData;
00547         op.indexData->indexCount = mNumVisibleBillboards * 6;
00548         op.indexData->indexStart = 0;
00549     }
00550 
00551     //-----------------------------------------------------------------------
00552     void BillboardSet::getWorldTransforms( Matrix4* xform ) const
00553     {
00554         *xform = _getParentNodeFullTransform(); 
00555     }
00556     //-----------------------------------------------------------------------
00557     const Quaternion& BillboardSet::getWorldOrientation(void) const
00558     {
00559         return mParentNode->_getDerivedOrientation();
00560     }
00561     //-----------------------------------------------------------------------
00562     const Vector3& BillboardSet::getWorldPosition(void) const
00563     {
00564         return mParentNode->_getDerivedPosition();
00565     }
00566     //-----------------------------------------------------------------------
00567     void BillboardSet::setAutoextend( bool autoextend )
00568     {
00569         mAutoExtendPool = autoextend;
00570     }
00571 
00572     //-----------------------------------------------------------------------
00573     bool BillboardSet::getAutoextend(void) const
00574     {
00575         return mAutoExtendPool;
00576     }
00577 
00578     //-----------------------------------------------------------------------
00579     void BillboardSet::setPoolSize( unsigned int size )
00580     {
00581         // Never shrink below size()
00582         size_t currSize = mBillboardPool.size();
00583 
00584         if( currSize < size )
00585         {
00586             this->increasePool(size);
00587 
00588             for( size_t i = currSize; i < size; ++i )
00589             {
00590                 // Add new items to the queue
00591                 mFreeBillboards.push_back( mBillboardPool[i] );
00592             }
00593 
00594             /* Allocate / reallocate vertex data
00595                Note that we allocate enough space for ALL the billboards in the pool, but only issue
00596                rendering operations for the sections relating to the active billboards
00597             */
00598 
00599             if (mVertexData)
00600                 delete mVertexData;
00601             if (mIndexData)
00602                 delete mIndexData;
00603 
00604             /* Alloc positions   ( 4 verts per billboard, 3 components )
00605                      colours     ( 1 x RGBA per vertex )
00606                      indices     ( 6 per billboard ( 2 tris ) )
00607                      tex. coords ( 2D coords, 4 per billboard )
00608             */
00609             mVertexData = new VertexData();
00610             mIndexData  = new IndexData();
00611 
00612             mVertexData->vertexCount = size * 4;
00613             mVertexData->vertexStart = 0;
00614 
00615             // Vertex declaration
00616             VertexDeclaration* decl = mVertexData->vertexDeclaration;
00617             VertexBufferBinding* binding = mVertexData->vertexBufferBinding;
00618 
00619             size_t offset = 0;
00620             decl->addElement(POSITION_BINDING, offset, VET_FLOAT3, VES_POSITION);
00621             //offset += VertexElement::getTypeSize(VET_FLOAT2);
00622             decl->addElement(COLOUR_BINDING, offset, VET_COLOUR, VES_DIFFUSE);
00623             decl->addElement(TEXCOORD_BINDING, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
00624 
00625             HardwareVertexBufferSharedPtr vbuf = 
00626                 HardwareBufferManager::getSingleton().createVertexBuffer(
00627                     decl->getVertexSize(POSITION_BINDING),
00628                     mVertexData->vertexCount, 
00629                     HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00630             // bind position and diffuses
00631             binding->setBinding(POSITION_BINDING, vbuf);
00632 
00633             vbuf = 
00634                 HardwareBufferManager::getSingleton().createVertexBuffer(
00635                     decl->getVertexSize(COLOUR_BINDING),
00636                     mVertexData->vertexCount, 
00637                     HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00638             // bind position and diffuses
00639             binding->setBinding(COLOUR_BINDING, vbuf);
00640 
00641             vbuf = 
00642                 HardwareBufferManager::getSingleton().createVertexBuffer(
00643                     decl->getVertexSize(TEXCOORD_BINDING),
00644                     mVertexData->vertexCount, 
00645                     HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00646             // bind position
00647             binding->setBinding(TEXCOORD_BINDING, vbuf);
00648 
00649             mIndexData->indexStart = 0;
00650             mIndexData->indexCount = size * 6;
00651 
00652             mIndexData->indexBuffer = HardwareBufferManager::getSingleton().
00653                 createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
00654                     mIndexData->indexCount,
00655                     HardwareBuffer::HBU_STATIC_WRITE_ONLY);
00656 
00657             /* Create indexes and tex coords (will be the same every frame)
00658                Using indexes because it means 1/3 less vertex transforms (4 instead of 6)
00659 
00660                Billboard layout relative to camera:
00661 
00662                 2-----3
00663                 |    /|
00664                 |  /  |
00665                 |/    |
00666                 0-----1
00667             */
00668 
00669             // Create template texcoord data
00670             Real texData[8] = {
00671                 0.0, 1.0,
00672                 1.0, 1.0,
00673                 0.0, 0.0,
00674                 1.0, 0.0 };
00675 
00676             ushort* pIdx = static_cast<ushort*>(
00677                 mIndexData->indexBuffer->lock(0,
00678                   mIndexData->indexBuffer->getSizeInBytes(),
00679                   HardwareBuffer::HBL_DISCARD) );
00680 
00681             vbuf = mVertexData->vertexBufferBinding->getBuffer(TEXCOORD_BINDING);
00682 
00683             Real* pT = static_cast<Real*>(
00684                 vbuf->lock(HardwareBuffer::HBL_DISCARD) );
00685 
00686             for(
00687                 size_t idx, idxOff, texOff, bboard = 0;
00688                 bboard < size;
00689                 ++bboard )
00690             {
00691                 // Do indexes
00692                 idx    = bboard * 6;
00693                 idxOff = bboard * 4;
00694                 texOff = bboard * 4 * 2;
00695 
00696                 pIdx[idx] = static_cast<unsigned short>(idxOff); // + 0;, for clarity
00697                 pIdx[idx+1] = static_cast<unsigned short>(idxOff + 1);
00698                 pIdx[idx+2] = static_cast<unsigned short>(idxOff + 3);
00699                 pIdx[idx+3] = static_cast<unsigned short>(idxOff + 0);
00700                 pIdx[idx+4] = static_cast<unsigned short>(idxOff + 3);
00701                 pIdx[idx+5] = static_cast<unsigned short>(idxOff + 2);
00702 
00703                 // Do tex coords
00704                 pT[texOff]   = texData[0];
00705                 pT[texOff+1] = texData[1];
00706                 pT[texOff+2] = texData[2];
00707                 pT[texOff+3] = texData[3];
00708                 pT[texOff+4] = texData[4];
00709                 pT[texOff+5] = texData[5];
00710                 pT[texOff+6] = texData[6];
00711                 pT[texOff+7] = texData[7];
00712             }
00713 
00714             vbuf->unlock();
00715             mIndexData->indexBuffer->unlock();
00716         }
00717     }
00718 
00719     //-----------------------------------------------------------------------
00720     unsigned int BillboardSet::getPoolSize(void) const
00721     {
00722         return static_cast< unsigned int >( mBillboardPool.size() );
00723     }
00724 
00725     //-----------------------------------------------------------------------
00726     void BillboardSet::_notifyBillboardResized(void)
00727     {
00728         mAllDefaultSize = false;
00729     }
00730 
00731     //-----------------------------------------------------------------------
00732     void BillboardSet::getParametricOffsets(
00733         Real& left, Real& right, Real& top, Real& bottom )
00734     {
00735         switch( mOriginType )
00736         {
00737         case BBO_TOP_LEFT:
00738             left = 0.0f;
00739             right = 1.0f;
00740             top = 0.0f;
00741             bottom = 1.0f;
00742             break;
00743 
00744         case BBO_TOP_CENTER:
00745             left = -0.5f;
00746             right = 0.5f;
00747             top = 0.0f;
00748             bottom = 1.0f;
00749             break;
00750 
00751         case BBO_TOP_RIGHT:
00752             left = -1.0f;
00753             right = 0.0f;
00754             top = 0.0f;
00755             bottom = 1.0f;
00756             break;
00757 
00758         case BBO_CENTER_LEFT:
00759             left = 0.0f;
00760             right = 1.0f;
00761             top = -0.5f;
00762             bottom = 0.5f;
00763             break;
00764 
00765         case BBO_CENTER:
00766             left = -0.5f;
00767             right = 0.5f;
00768             top = -0.5f;
00769             bottom = 0.5f;
00770             break;
00771 
00772         case BBO_CENTER_RIGHT:
00773             left = -1.0f;
00774             right = 0.0f;
00775             top = -0.5f;
00776             bottom = 0.5f;
00777             break;
00778 
00779         case BBO_BOTTOM_LEFT:
00780             left = 0.0f;
00781             right = 1.0f;
00782             top = -1.0f;
00783             bottom = 0.0f;
00784             break;
00785 
00786         case BBO_BOTTOM_CENTER:
00787             left = -0.5f;
00788             right = 0.5f;
00789             top = -1.0f;
00790             bottom = 0.0f;
00791             break;
00792 
00793         case BBO_BOTTOM_RIGHT:
00794             left = -1.0f;
00795             right = 0.0f;
00796             top = -1.0f;
00797             bottom = 0.0f;
00798             break;
00799         }
00800     }
00801     //-----------------------------------------------------------------------
00802     bool BillboardSet::getCullIndividually(void) const
00803     {
00804         return mCullIndividual;
00805     }
00806     //-----------------------------------------------------------------------
00807     void BillboardSet::setCullIndividually(bool cullIndividual)
00808     {
00809         mCullIndividual = cullIndividual;
00810     }
00811     //-----------------------------------------------------------------------
00812     bool BillboardSet::billboardVisible(Camera* cam, ActiveBillboardList::iterator bill)
00813     {
00814         // Return always visible if not culling individually
00815         if (!mCullIndividual) return true;
00816 
00817         // Cull based on sphere (have to transform less)
00818         Sphere sph;
00819         Matrix4 xworld;
00820 
00821         getWorldTransforms(&xworld);
00822 
00823         sph.setCenter(xworld * (*bill)->mPosition);
00824 
00825         if ((*bill)->mOwnDimensions)
00826         {
00827             sph.setRadius(std::max((*bill)->mWidth, (*bill)->mHeight));
00828         }
00829         else
00830         {
00831             sph.setRadius(std::max(mDefaultWidth, mDefaultHeight));
00832         }
00833 
00834         return cam->isVisible(sph);
00835         
00836     }
00837     //-----------------------------------------------------------------------
00838     void BillboardSet::increasePool(unsigned int size)
00839     {
00840         size_t oldSize = mBillboardPool.size();
00841 
00842         // Increase size
00843         mBillboardPool.reserve(size);
00844         mBillboardPool.resize(size);
00845 
00846         // Create new billboards
00847         for( size_t i = oldSize; i < size; ++i )
00848             mBillboardPool[i] = new Billboard();
00849 
00850     }
00851     //-----------------------------------------------------------------------
00852     void BillboardSet:: genBillboardAxes(Camera& cam, Vector3* pX, Vector3 *pY, const Billboard* pBill)
00853     {
00854         // Default behaviour is that billboards are in local node space
00855         // so orientation of camera (in world space) must be reverse-transformed 
00856         // into node space to generate the axes
00857 
00858         Quaternion invTransform = mParentNode->_getDerivedOrientation().Inverse();
00859         Quaternion camQ;
00860 
00861         switch (mBillboardType)
00862         {
00863         case BBT_POINT:
00864             // Get camera world axes for X and Y (depth is irrelevant)
00865             camQ = cam.getDerivedOrientation();
00866             // Convert into billboard local space
00867             camQ = invTransform * camQ;
00868             *pX = camQ * Vector3::UNIT_X;
00869             *pY = camQ * Vector3::UNIT_Y;
00870             break;
00871         case BBT_ORIENTED_COMMON:
00872             // Y-axis is common direction
00873             // X-axis is cross with camera direction 
00874             *pY = mCommonDirection;
00875             // Convert into billboard local space
00876             *pX = invTransform * cam.getDerivedDirection().crossProduct(*pY);
00877             
00878             break;
00879         case BBT_ORIENTED_SELF:
00880             // Y-axis is direction
00881             // X-axis is cross with camera direction 
00882             *pY = pBill->mDirection;
00883             // Convert into billboard local space
00884             *pX = invTransform * cam.getDerivedDirection().crossProduct(*pY);
00885 
00886             break;
00887         }
00888 
00889     }
00890     //-----------------------------------------------------------------------
00891     void BillboardSet::setBillboardType(BillboardType bbt)
00892     {
00893         mBillboardType = bbt;
00894     }
00895     //-----------------------------------------------------------------------
00896     BillboardType BillboardSet::getBillboardType(void) const
00897     {
00898         return mBillboardType;
00899     }
00900     //-----------------------------------------------------------------------
00901     void BillboardSet::setCommonDirection(const Vector3& vec)
00902     {
00903         mCommonDirection = vec;
00904     }
00905     //-----------------------------------------------------------------------
00906     const Vector3& BillboardSet::getCommonDirection(void) const
00907     {
00908         return mCommonDirection;
00909     }
00910     //-----------------------------------------------------------------------
00911     void BillboardSet::genVertices(Real **pPos, RGBA** pCol, Real **pTex, const Vector3* offsets, const Billboard* pBillboard)
00912     {
00913         // Texcoords
00914 
00915         if (!mFixedTextureCoords)
00916         {
00917             // Create template texcoord data
00918             Real texData[8] = {
00919                 -0.5, 0.5,
00920                  0.5, 0.5,
00921                 -0.5,-0.5,
00922                  0.5,-0.5 };
00923 
00924             const Real      rotation = pBillboard->mRotation;
00925             const Real      cos_rot  = Math::Cos(rotation);
00926             const Real      sin_rot  = Math::Sin(rotation);
00927         
00928             *(*pTex)++ = (cos_rot * texData[0]) + (sin_rot * texData[1]) + 0.5;
00929             *(*pTex)++ = (sin_rot * texData[0]) - (cos_rot * texData[1]) + 0.5;
00930 
00931             *(*pTex)++ = (cos_rot * texData[2]) + (sin_rot * texData[3]) + 0.5;
00932             *(*pTex)++ = (sin_rot * texData[2]) - (cos_rot * texData[3]) + 0.5;
00933             
00934             *(*pTex)++ = (cos_rot * texData[4]) + (sin_rot * texData[5]) + 0.5;
00935             *(*pTex)++ = (sin_rot * texData[4]) - (cos_rot * texData[5]) + 0.5;
00936             
00937             *(*pTex)++ = (cos_rot * texData[6]) + (sin_rot * texData[7]) + 0.5;
00938             *(*pTex)++ = (sin_rot * texData[6]) - (cos_rot * texData[7]) + 0.5;
00939         }
00940 
00941         // Positions
00942 
00943         // Left-top
00944         *(*pPos)++ = offsets[0].x + pBillboard->mPosition.x;
00945         *(*pPos)++ = offsets[0].y + pBillboard->mPosition.y;
00946         *(*pPos)++ = offsets[0].z + pBillboard->mPosition.z;
00947         // Right-top
00948         *(*pPos)++ = offsets[1].x + pBillboard->mPosition.x;
00949         *(*pPos)++ = offsets[1].y + pBillboard->mPosition.y;
00950         *(*pPos)++ = offsets[1].z + pBillboard->mPosition.z;
00951         // Left-bottom
00952         *(*pPos)++ = offsets[2].x + pBillboard->mPosition.x;
00953         *(*pPos)++ = offsets[2].y + pBillboard->mPosition.y;
00954         *(*pPos)++ = offsets[2].z + pBillboard->mPosition.z;
00955         // Right-bottom
00956         *(*pPos)++ = offsets[3].x + pBillboard->mPosition.x;
00957         *(*pPos)++ = offsets[3].y + pBillboard->mPosition.y;
00958         *(*pPos)++ = offsets[3].z + pBillboard->mPosition.z;
00959 
00960         // Update colours
00961         RGBA colour;
00962         Root::getSingleton().convertColourValue(pBillboard->mColour, &colour);
00963 
00964         *(*pCol)++ = colour;
00965         *(*pCol)++ = colour;
00966         *(*pCol)++ = colour;
00967         *(*pCol)++ = colour;
00968 
00969     }
00970     //-----------------------------------------------------------------------
00971     void BillboardSet::genVertOffsets(Real inleft, Real inright, Real intop, Real inbottom,
00972         Real width, Real height, const Vector3& x, const Vector3& y, Vector3* pDestVec)
00973     {
00974         Vector3 vLeftOff, vRightOff, vTopOff, vBottomOff;
00975         /* Calculate default offsets. Scale the axes by
00976            parametric offset and dimensions, ready to be added to
00977            positions.
00978         */
00979 
00980         vLeftOff   = x * ( inleft   * width );
00981         vRightOff  = x * ( inright  * width );
00982         vTopOff    = y * ( intop   * height );
00983         vBottomOff = y * ( inbottom * height );
00984 
00985         // Make final offsets to vertex positions
00986         pDestVec[0] = vLeftOff  + vTopOff;
00987         pDestVec[1] = vRightOff + vTopOff;
00988         pDestVec[2] = vLeftOff  + vBottomOff;
00989         pDestVec[3] = vRightOff + vBottomOff;
00990 
00991     }
00992     //-----------------------------------------------------------------------
00993     const String& BillboardSet::getName(void) const
00994     {
00995         return mName;
00996     }
00997     //-----------------------------------------------------------------------
00998     const String& BillboardSet::getMovableType(void) const
00999     {
01000         return msMovableType;
01001     }
01002     //-----------------------------------------------------------------------
01003     Real BillboardSet::getSquaredViewDepth(const Camera* cam) const
01004     {
01005         assert(mParentNode);
01006         return mParentNode->getSquaredViewDepth(cam);
01007     }
01008     //-----------------------------------------------------------------------
01009     Real BillboardSet::getBoundingRadius(void) const
01010     {
01011         return mBoundingRadius;
01012     }
01013     //-----------------------------------------------------------------------
01014     const LightList& BillboardSet::getLights(void) const
01015     {
01016         // It's actually quite unlikely that this will be called, 
01017         // because most billboards are unlit, but here we go anyway
01018         return mParentNode->getLights();
01019     }
01020 
01021 }

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:02 2004