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