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

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:21:53 2004