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