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