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 29 // Thanks to Vincent Cantin (karmaGfa) for the original implementation of this 30 // class, although it has now been mostly rewritten 31 32 #include "OgreStableHeaders.h" 33 #include "OgreBillboardChain.h" 34 #include "OgreViewport.h" 35 36 #include <limits> 37 38 namespace Ogre { 39 const size_t BillboardChain::SEGMENT_EMPTY = std::numeric_limits<size_t>::max(); 40 //----------------------------------------------------------------------- Element()41 BillboardChain::Element::Element() 42 { 43 } 44 //----------------------------------------------------------------------- Element(const Vector3 & _position,Real _width,Real _texCoord,const ColourValue & _colour,const Quaternion & _orientation)45 BillboardChain::Element::Element(const Vector3 &_position, 46 Real _width, 47 Real _texCoord, 48 const ColourValue &_colour, 49 const Quaternion &_orientation) : 50 position(_position), 51 width(_width), 52 texCoord(_texCoord), 53 colour(_colour), 54 orientation(_orientation) 55 { 56 } 57 //----------------------------------------------------------------------- BillboardChain(const String & name,size_t maxElements,size_t numberOfChains,bool useTextureCoords,bool useColours,bool dynamic)58 BillboardChain::BillboardChain(const String& name, size_t maxElements, 59 size_t numberOfChains, bool useTextureCoords, bool useColours, bool dynamic) 60 :MovableObject(name), 61 mMaxElementsPerChain(maxElements), 62 mChainCount(numberOfChains), 63 mUseTexCoords(useTextureCoords), 64 mUseVertexColour(useColours), 65 mDynamic(dynamic), 66 mVertexDeclDirty(true), 67 mBuffersNeedRecreating(true), 68 mBoundsDirty(true), 69 mIndexContentDirty(true), 70 mVertexContentDirty(true), 71 mRadius(0.0f), 72 mTexCoordDir(TCD_U), 73 mVertexCameraUsed(0), 74 mFaceCamera(true), 75 mNormalBase(Vector3::UNIT_X) 76 { 77 mVertexData.reset(new VertexData()); 78 mIndexData.reset(new IndexData()); 79 80 mOtherTexCoordRange[0] = 0.0f; 81 mOtherTexCoordRange[1] = 1.0f; 82 83 setupChainContainers(); 84 85 mVertexData->vertexStart = 0; 86 // index data set up later 87 // set basic white material 88 mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false); 89 mMaterial->load(); 90 } 91 92 BillboardChain::~BillboardChain() = default; // ensure unique_ptr destructors are in cpp 93 94 //----------------------------------------------------------------------- setupChainContainers(void)95 void BillboardChain::setupChainContainers(void) 96 { 97 // Allocate enough space for everything 98 mChainElementList.resize(mChainCount * mMaxElementsPerChain); 99 mVertexData->vertexCount = mChainElementList.size() * 2; 100 101 // Configure chains 102 mChainSegmentList.resize(mChainCount); 103 for (size_t i = 0; i < mChainCount; ++i) 104 { 105 ChainSegment& seg = mChainSegmentList[i]; 106 seg.start = i * mMaxElementsPerChain; 107 seg.tail = seg.head = SEGMENT_EMPTY; 108 109 } 110 111 112 } 113 //----------------------------------------------------------------------- setupVertexDeclaration(void)114 void BillboardChain::setupVertexDeclaration(void) 115 { 116 if (mVertexDeclDirty) 117 { 118 VertexDeclaration* decl = mVertexData->vertexDeclaration; 119 decl->removeAllElements(); 120 121 size_t offset = 0; 122 // Add a description for the buffer of the positions of the vertices 123 decl->addElement(0, offset, VET_FLOAT3, VES_POSITION); 124 offset += VertexElement::getTypeSize(VET_FLOAT3); 125 126 if (mUseVertexColour) 127 { 128 decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE); 129 offset += VertexElement::getTypeSize(VET_COLOUR); 130 } 131 132 if (mUseTexCoords) 133 { 134 decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); 135 } 136 137 if (!mUseTexCoords && !mUseVertexColour) 138 { 139 LogManager::getSingleton().logError( 140 "BillboardChain '" + mName + "' is using neither " 141 "texture coordinates nor vertex colours; it will not be " 142 "visible on some rendering APIs so you should change this " 143 "so you use one or the other."); 144 } 145 mVertexDeclDirty = false; 146 } 147 } 148 //----------------------------------------------------------------------- setupBuffers(void)149 void BillboardChain::setupBuffers(void) 150 { 151 setupVertexDeclaration(); 152 if (mBuffersNeedRecreating) 153 { 154 // Create the vertex buffer (always dynamic due to the camera adjust) 155 HardwareVertexBufferSharedPtr pBuffer = 156 HardwareBufferManager::getSingleton().createVertexBuffer( 157 mVertexData->vertexDeclaration->getVertexSize(0), 158 mVertexData->vertexCount, 159 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE); 160 161 // (re)Bind the buffer 162 // Any existing buffer will lose its reference count and be destroyed 163 mVertexData->vertexBufferBinding->setBinding(0, pBuffer); 164 165 mIndexData->indexBuffer = 166 HardwareBufferManager::getSingleton().createIndexBuffer( 167 HardwareIndexBuffer::IT_16BIT, 168 mChainCount * mMaxElementsPerChain * 6, // max we can use 169 mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : HardwareBuffer::HBU_STATIC_WRITE_ONLY); 170 // NB we don't set the indexCount on IndexData here since we will 171 // probably use less than the maximum number of indices 172 173 mBuffersNeedRecreating = false; 174 } 175 } 176 //----------------------------------------------------------------------- setMaxChainElements(size_t maxElements)177 void BillboardChain::setMaxChainElements(size_t maxElements) 178 { 179 mMaxElementsPerChain = maxElements; 180 setupChainContainers(); 181 mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true; 182 } 183 //----------------------------------------------------------------------- setNumberOfChains(size_t numChains)184 void BillboardChain::setNumberOfChains(size_t numChains) 185 { 186 mChainCount = numChains; 187 setupChainContainers(); 188 mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true; 189 } 190 //----------------------------------------------------------------------- setUseTextureCoords(bool use)191 void BillboardChain::setUseTextureCoords(bool use) 192 { 193 mUseTexCoords = use; 194 mVertexDeclDirty = mBuffersNeedRecreating = true; 195 mIndexContentDirty = mVertexContentDirty = true; 196 } 197 //----------------------------------------------------------------------- setTextureCoordDirection(BillboardChain::TexCoordDirection dir)198 void BillboardChain::setTextureCoordDirection(BillboardChain::TexCoordDirection dir) 199 { 200 mTexCoordDir = dir; 201 mVertexContentDirty = true; 202 } 203 //----------------------------------------------------------------------- setOtherTextureCoordRange(Real start,Real end)204 void BillboardChain::setOtherTextureCoordRange(Real start, Real end) 205 { 206 mOtherTexCoordRange[0] = start; 207 mOtherTexCoordRange[1] = end; 208 mVertexContentDirty = true; 209 } 210 //----------------------------------------------------------------------- setUseVertexColours(bool use)211 void BillboardChain::setUseVertexColours(bool use) 212 { 213 mUseVertexColour = use; 214 mVertexDeclDirty = mBuffersNeedRecreating = true; 215 mIndexContentDirty = mVertexContentDirty = true; 216 } 217 //----------------------------------------------------------------------- setDynamic(bool dyn)218 void BillboardChain::setDynamic(bool dyn) 219 { 220 mDynamic = dyn; 221 mBuffersNeedRecreating = mIndexContentDirty = mVertexContentDirty = true; 222 } 223 //----------------------------------------------------------------------- addChainElement(size_t chainIndex,const BillboardChain::Element & dtls)224 void BillboardChain::addChainElement(size_t chainIndex, 225 const BillboardChain::Element& dtls) 226 { 227 228 if (chainIndex >= mChainCount) 229 { 230 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 231 "chainIndex out of bounds", 232 "BillboardChain::addChainElement"); 233 } 234 ChainSegment& seg = mChainSegmentList[chainIndex]; 235 if (seg.head == SEGMENT_EMPTY) 236 { 237 // Tail starts at end, head grows backwards 238 seg.tail = mMaxElementsPerChain - 1; 239 seg.head = seg.tail; 240 } 241 else 242 { 243 if (seg.head == 0) 244 { 245 // Wrap backwards 246 seg.head = mMaxElementsPerChain - 1; 247 } 248 else 249 { 250 // Just step backward 251 --seg.head; 252 } 253 // Run out of elements? 254 if (seg.head == seg.tail) 255 { 256 // Move tail backwards too, losing the end of the segment and re-using 257 // it in the head 258 if (seg.tail == 0) 259 seg.tail = mMaxElementsPerChain - 1; 260 else 261 --seg.tail; 262 } 263 } 264 265 // Set the details 266 mChainElementList[seg.start + seg.head] = dtls; 267 268 mVertexContentDirty = true; 269 mIndexContentDirty = true; 270 mBoundsDirty = true; 271 // tell parent node to update bounds 272 if (mParentNode) 273 mParentNode->needUpdate(); 274 275 } 276 //----------------------------------------------------------------------- removeChainElement(size_t chainIndex)277 void BillboardChain::removeChainElement(size_t chainIndex) 278 { 279 if (chainIndex >= mChainCount) 280 { 281 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 282 "chainIndex out of bounds", 283 "BillboardChain::removeChainElement"); 284 } 285 ChainSegment& seg = mChainSegmentList[chainIndex]; 286 if (seg.head == SEGMENT_EMPTY) 287 return; // do nothing, nothing to remove 288 289 290 if (seg.tail == seg.head) 291 { 292 // last item 293 seg.head = seg.tail = SEGMENT_EMPTY; 294 } 295 else if (seg.tail == 0) 296 { 297 seg.tail = mMaxElementsPerChain - 1; 298 } 299 else 300 { 301 --seg.tail; 302 } 303 304 // we removed an entry so indexes need updating 305 mVertexContentDirty = true; 306 mIndexContentDirty = true; 307 mBoundsDirty = true; 308 // tell parent node to update bounds 309 if (mParentNode) 310 mParentNode->needUpdate(); 311 312 } 313 //----------------------------------------------------------------------- clearChain(size_t chainIndex)314 void BillboardChain::clearChain(size_t chainIndex) 315 { 316 if (chainIndex >= mChainCount) 317 { 318 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 319 "chainIndex out of bounds", 320 "BillboardChain::clearChain"); 321 } 322 ChainSegment& seg = mChainSegmentList[chainIndex]; 323 324 // Just reset head & tail 325 seg.tail = seg.head = SEGMENT_EMPTY; 326 327 // we removed an entry so indexes need updating 328 mVertexContentDirty = true; 329 mIndexContentDirty = true; 330 mBoundsDirty = true; 331 // tell parent node to update bounds 332 if (mParentNode) 333 mParentNode->needUpdate(); 334 335 } 336 //----------------------------------------------------------------------- clearAllChains(void)337 void BillboardChain::clearAllChains(void) 338 { 339 for (size_t i = 0; i < mChainCount; ++i) 340 { 341 clearChain(i); 342 } 343 344 } 345 //----------------------------------------------------------------------- setFaceCamera(bool faceCamera,const Vector3 & normalVector)346 void BillboardChain::setFaceCamera( bool faceCamera, const Vector3 &normalVector ) 347 { 348 mFaceCamera = faceCamera; 349 mNormalBase = normalVector.normalisedCopy(); 350 mVertexContentDirty = true; 351 } 352 //----------------------------------------------------------------------- updateChainElement(size_t chainIndex,size_t elementIndex,const BillboardChain::Element & dtls)353 void BillboardChain::updateChainElement(size_t chainIndex, size_t elementIndex, 354 const BillboardChain::Element& dtls) 355 { 356 if (chainIndex >= mChainCount) 357 { 358 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 359 "chainIndex out of bounds", 360 "BillboardChain::updateChainElement"); 361 } 362 ChainSegment& seg = mChainSegmentList[chainIndex]; 363 if (seg.head == SEGMENT_EMPTY) 364 { 365 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 366 "Chain segment is empty", 367 "BillboardChain::updateChainElement"); 368 } 369 370 size_t idx = seg.head + elementIndex; 371 // adjust for the edge and start 372 idx = (idx % mMaxElementsPerChain) + seg.start; 373 374 mChainElementList[idx] = dtls; 375 376 mVertexContentDirty = true; 377 mBoundsDirty = true; 378 // tell parent node to update bounds 379 if (mParentNode) 380 mParentNode->needUpdate(); 381 382 383 } 384 //----------------------------------------------------------------------- 385 const BillboardChain::Element& getChainElement(size_t chainIndex,size_t elementIndex) const386 BillboardChain::getChainElement(size_t chainIndex, size_t elementIndex) const 387 { 388 389 if (chainIndex >= mChainCount) 390 { 391 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 392 "chainIndex out of bounds", 393 "BillboardChain::getChainElement"); 394 } 395 const ChainSegment& seg = mChainSegmentList[chainIndex]; 396 if (seg.head == SEGMENT_EMPTY) 397 { 398 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 399 "Chain segment is empty", 400 "BillboardChain::getChainElement"); 401 } 402 403 size_t idx = seg.head + elementIndex; 404 // adjust for the edge and start 405 idx = (idx % mMaxElementsPerChain) + seg.start; 406 407 return mChainElementList[idx]; 408 } 409 //----------------------------------------------------------------------- getNumChainElements(size_t chainIndex) const410 size_t BillboardChain::getNumChainElements(size_t chainIndex) const 411 { 412 if (chainIndex >= mChainCount) 413 { 414 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 415 "chainIndex out of bounds", 416 "BillboardChain::getNumChainElements"); 417 } 418 const ChainSegment& seg = mChainSegmentList[chainIndex]; 419 420 if (seg.head == SEGMENT_EMPTY) 421 { 422 return 0; 423 } 424 else if (seg.tail < seg.head) 425 { 426 return seg.tail - seg.head + mMaxElementsPerChain + 1; 427 } 428 else 429 { 430 return seg.tail - seg.head + 1; 431 } 432 } 433 //----------------------------------------------------------------------- updateBoundingBox(void) const434 void BillboardChain::updateBoundingBox(void) const 435 { 436 if (mBoundsDirty) 437 { 438 mAABB.setNull(); 439 Vector3 widthVector; 440 for (ChainSegmentList::const_iterator segi = mChainSegmentList.begin(); 441 segi != mChainSegmentList.end(); ++segi) 442 { 443 const ChainSegment& seg = *segi; 444 445 if (seg.head != SEGMENT_EMPTY) 446 { 447 448 for(size_t e = seg.head; ; ++e) // until break 449 { 450 // Wrap forwards 451 if (e == mMaxElementsPerChain) 452 e = 0; 453 454 const Element& elem = mChainElementList[seg.start + e]; 455 456 widthVector.x = widthVector.y = widthVector.z = elem.width; 457 mAABB.merge(elem.position - widthVector); 458 mAABB.merge(elem.position + widthVector); 459 460 if (e == seg.tail) 461 break; 462 463 } 464 } 465 466 } 467 468 // Set the current radius 469 if (mAABB.isNull()) 470 { 471 mRadius = 0.0f; 472 } 473 else 474 { 475 mRadius = Math::Sqrt( 476 std::max(mAABB.getMinimum().squaredLength(), 477 mAABB.getMaximum().squaredLength())); 478 } 479 480 mBoundsDirty = false; 481 } 482 } 483 //----------------------------------------------------------------------- updateVertexBuffer(Camera * cam)484 void BillboardChain::updateVertexBuffer(Camera* cam) 485 { 486 setupBuffers(); 487 488 // The contents of the vertex buffer are correct if they are not dirty 489 // and the camera used to build the vertex buffer is still the current 490 // camera. 491 if (!mVertexContentDirty && mVertexCameraUsed == cam) 492 return; 493 494 HardwareVertexBufferSharedPtr pBuffer = 495 mVertexData->vertexBufferBinding->getBuffer(0); 496 HardwareBufferLockGuard vertexLock(pBuffer, HardwareBuffer::HBL_DISCARD); 497 498 const Vector3& camPos = cam->getDerivedPosition(); 499 Vector3 eyePos = mParentNode->convertWorldToLocalPosition(camPos); 500 501 Vector3 chainTangent; 502 for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); 503 segi != mChainSegmentList.end(); ++segi) 504 { 505 ChainSegment& seg = *segi; 506 507 // Skip 0 or 1 element segment counts 508 if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) 509 { 510 size_t laste = seg.head; 511 for (size_t e = seg.head; ; ++e) // until break 512 { 513 // Wrap forwards 514 if (e == mMaxElementsPerChain) 515 e = 0; 516 517 Element& elem = mChainElementList[e + seg.start]; 518 assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); 519 uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); 520 521 // Determine base pointer to vertex #1 522 void* pBase = static_cast<void*>( 523 static_cast<char*>(vertexLock.pData) + 524 pBuffer->getVertexSize() * baseIdx); 525 526 // Get index of next item 527 size_t nexte = e + 1; 528 if (nexte == mMaxElementsPerChain) 529 nexte = 0; 530 531 if (e == seg.head) 532 { 533 // No laste, use next item 534 chainTangent = mChainElementList[nexte + seg.start].position - elem.position; 535 } 536 else if (e == seg.tail) 537 { 538 // No nexte, use only last item 539 chainTangent = elem.position - mChainElementList[laste + seg.start].position; 540 } 541 else 542 { 543 // A mid position, use tangent across both prev and next 544 chainTangent = mChainElementList[nexte + seg.start].position - mChainElementList[laste + seg.start].position; 545 546 } 547 548 Vector3 vP1ToEye; 549 550 if( mFaceCamera ) 551 vP1ToEye = eyePos - elem.position; 552 else 553 vP1ToEye = elem.orientation * mNormalBase; 554 555 Vector3 vPerpendicular = chainTangent.crossProduct(vP1ToEye); 556 vPerpendicular.normalise(); 557 vPerpendicular *= (elem.width * 0.5f); 558 559 Vector3 pos0 = elem.position - vPerpendicular; 560 Vector3 pos1 = elem.position + vPerpendicular; 561 562 float* pFloat = static_cast<float*>(pBase); 563 // pos1 564 *pFloat++ = pos0.x; 565 *pFloat++ = pos0.y; 566 *pFloat++ = pos0.z; 567 568 pBase = static_cast<void*>(pFloat); 569 570 if (mUseVertexColour) 571 { 572 RGBA* pCol = static_cast<RGBA*>(pBase); 573 Root::getSingleton().convertColourValue(elem.colour, pCol); 574 pCol++; 575 pBase = static_cast<void*>(pCol); 576 } 577 578 if (mUseTexCoords) 579 { 580 pFloat = static_cast<float*>(pBase); 581 if (mTexCoordDir == TCD_U) 582 { 583 *pFloat++ = elem.texCoord; 584 *pFloat++ = mOtherTexCoordRange[0]; 585 } 586 else 587 { 588 *pFloat++ = mOtherTexCoordRange[0]; 589 *pFloat++ = elem.texCoord; 590 } 591 pBase = static_cast<void*>(pFloat); 592 } 593 594 // pos2 595 pFloat = static_cast<float*>(pBase); 596 *pFloat++ = pos1.x; 597 *pFloat++ = pos1.y; 598 *pFloat++ = pos1.z; 599 pBase = static_cast<void*>(pFloat); 600 601 if (mUseVertexColour) 602 { 603 RGBA* pCol = static_cast<RGBA*>(pBase); 604 Root::getSingleton().convertColourValue(elem.colour, pCol); 605 pCol++; 606 pBase = static_cast<void*>(pCol); 607 } 608 609 if (mUseTexCoords) 610 { 611 pFloat = static_cast<float*>(pBase); 612 if (mTexCoordDir == TCD_U) 613 { 614 *pFloat++ = elem.texCoord; 615 *pFloat++ = mOtherTexCoordRange[1]; 616 } 617 else 618 { 619 *pFloat++ = mOtherTexCoordRange[1]; 620 *pFloat++ = elem.texCoord; 621 } 622 } 623 624 if (e == seg.tail) 625 break; // last one 626 627 laste = e; 628 629 } // element 630 } // segment valid? 631 632 } // each segment 633 634 mVertexCameraUsed = cam; 635 mVertexContentDirty = false; 636 } 637 //----------------------------------------------------------------------- updateIndexBuffer(void)638 void BillboardChain::updateIndexBuffer(void) 639 { 640 641 setupBuffers(); 642 if (mIndexContentDirty) 643 { 644 HardwareBufferLockGuard indexLock(mIndexData->indexBuffer, HardwareBuffer::HBL_DISCARD); 645 uint16* pShort = static_cast<uint16*>(indexLock.pData); 646 mIndexData->indexCount = 0; 647 // indexes 648 for (ChainSegmentList::iterator segi = mChainSegmentList.begin(); 649 segi != mChainSegmentList.end(); ++segi) 650 { 651 ChainSegment& seg = *segi; 652 653 // Skip 0 or 1 element segment counts 654 if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail) 655 { 656 // Start from head + 1 since it's only useful in pairs 657 size_t laste = seg.head; 658 while(1) // until break 659 { 660 size_t e = laste + 1; 661 // Wrap forwards 662 if (e == mMaxElementsPerChain) 663 e = 0; 664 // indexes of this element are (e * 2) and (e * 2) + 1 665 // indexes of the last element are the same, -2 666 assert (((e + seg.start) * 2) < 65536 && "Too many elements!"); 667 uint16 baseIdx = static_cast<uint16>((e + seg.start) * 2); 668 uint16 lastBaseIdx = static_cast<uint16>((laste + seg.start) * 2); 669 *pShort++ = lastBaseIdx; 670 *pShort++ = lastBaseIdx + 1; 671 *pShort++ = baseIdx; 672 *pShort++ = lastBaseIdx + 1; 673 *pShort++ = baseIdx + 1; 674 *pShort++ = baseIdx; 675 676 mIndexData->indexCount += 6; 677 678 679 if (e == seg.tail) 680 break; // last one 681 682 laste = e; 683 684 } 685 } 686 687 } 688 689 mIndexContentDirty = false; 690 } 691 692 } 693 //----------------------------------------------------------------------- getSquaredViewDepth(const Camera * cam) const694 Real BillboardChain::getSquaredViewDepth(const Camera* cam) const 695 { 696 return (cam->getDerivedPosition() - mAABB.getCenter()).squaredLength(); 697 } 698 //----------------------------------------------------------------------- getBoundingRadius(void) const699 Real BillboardChain::getBoundingRadius(void) const 700 { 701 return mRadius; 702 } 703 //----------------------------------------------------------------------- getBoundingBox(void) const704 const AxisAlignedBox& BillboardChain::getBoundingBox(void) const 705 { 706 updateBoundingBox(); 707 return mAABB; 708 } 709 //----------------------------------------------------------------------- getMaterial(void) const710 const MaterialPtr& BillboardChain::getMaterial(void) const 711 { 712 return mMaterial; 713 } 714 //----------------------------------------------------------------------- setMaterialName(const String & name,const String & groupName)715 void BillboardChain::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */) 716 { 717 mMaterial = MaterialManager::getSingleton().getByName(name, groupName); 718 719 if (!mMaterial) 720 { 721 LogManager::getSingleton().logMessage("Can't assign material " + name + 722 " to BillboardChain " + mName + " because this " 723 "Material does not exist in group "+groupName+". Have you forgotten to define it in a " 724 ".material script?", LML_CRITICAL); 725 mMaterial = MaterialManager::getSingleton().getDefaultMaterial(false); 726 } 727 // Ensure new material loaded (will not load again if already loaded) 728 mMaterial->load(); 729 } 730 //----------------------------------------------------------------------- getMovableType(void) const731 const String& BillboardChain::getMovableType(void) const 732 { 733 return BillboardChainFactory::FACTORY_TYPE_NAME; 734 } 735 //----------------------------------------------------------------------- _updateRenderQueue(RenderQueue * queue)736 void BillboardChain::_updateRenderQueue(RenderQueue* queue) 737 { 738 updateIndexBuffer(); 739 740 if (mIndexData->indexCount > 0) 741 { 742 if (mRenderQueuePrioritySet) 743 queue->addRenderable(this, mRenderQueueID, mRenderQueuePriority); 744 else if (mRenderQueueIDSet) 745 queue->addRenderable(this, mRenderQueueID); 746 else 747 queue->addRenderable(this); 748 } 749 750 } 751 //----------------------------------------------------------------------- getRenderOperation(RenderOperation & op)752 void BillboardChain::getRenderOperation(RenderOperation& op) 753 { 754 op.indexData = mIndexData.get(); 755 op.operationType = RenderOperation::OT_TRIANGLE_LIST; 756 op.srcRenderable = this; 757 op.useIndexes = true; 758 op.vertexData = mVertexData.get(); 759 } 760 //----------------------------------------------------------------------- preRender(SceneManager * sm,RenderSystem * rsys)761 bool BillboardChain::preRender(SceneManager* sm, RenderSystem* rsys) 762 { 763 // Retrieve the current viewport from the scene manager. 764 // The viewport is only valid during a viewport update. 765 Viewport *currentViewport = sm->getCurrentViewport(); 766 if( !currentViewport ) 767 return false; 768 769 updateVertexBuffer(currentViewport->getCamera()); 770 return true; 771 } 772 //----------------------------------------------------------------------- getWorldTransforms(Matrix4 * xform) const773 void BillboardChain::getWorldTransforms(Matrix4* xform) const 774 { 775 *xform = _getParentNodeFullTransform(); 776 } 777 //----------------------------------------------------------------------- getLights(void) const778 const LightList& BillboardChain::getLights(void) const 779 { 780 return queryLights(); 781 } 782 //--------------------------------------------------------------------- visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)783 void BillboardChain::visitRenderables(Renderable::Visitor* visitor, 784 bool debugRenderables) 785 { 786 // only one renderable 787 visitor->visit(this, 0, false); 788 } 789 //----------------------------------------------------------------------- 790 //----------------------------------------------------------------------- 791 String BillboardChainFactory::FACTORY_TYPE_NAME = "BillboardChain"; 792 //----------------------------------------------------------------------- getType(void) const793 const String& BillboardChainFactory::getType(void) const 794 { 795 return FACTORY_TYPE_NAME; 796 } 797 //----------------------------------------------------------------------- createInstanceImpl(const String & name,const NameValuePairList * params)798 MovableObject* BillboardChainFactory::createInstanceImpl( const String& name, 799 const NameValuePairList* params) 800 { 801 size_t maxElements = 20; 802 size_t numberOfChains = 1; 803 bool useTex = true; 804 bool useCol = true; 805 bool dynamic = true; 806 // optional params 807 if (params != 0) 808 { 809 NameValuePairList::const_iterator ni = params->find("maxElements"); 810 if (ni != params->end()) 811 { 812 maxElements = StringConverter::parseSizeT(ni->second); 813 } 814 ni = params->find("numberOfChains"); 815 if (ni != params->end()) 816 { 817 numberOfChains = StringConverter::parseSizeT(ni->second); 818 } 819 ni = params->find("useTextureCoords"); 820 if (ni != params->end()) 821 { 822 useTex = StringConverter::parseBool(ni->second); 823 } 824 ni = params->find("useVertexColours"); 825 if (ni != params->end()) 826 { 827 useCol = StringConverter::parseBool(ni->second); 828 } 829 ni = params->find("dynamic"); 830 if (ni != params->end()) 831 { 832 dynamic = StringConverter::parseBool(ni->second); 833 } 834 835 } 836 837 return OGRE_NEW BillboardChain(name, maxElements, numberOfChains, useTex, useCol, dynamic); 838 839 } 840 //----------------------------------------------------------------------- destroyInstance(MovableObject * obj)841 void BillboardChainFactory::destroyInstance( MovableObject* obj) 842 { 843 OGRE_DELETE obj; 844 } 845 846 } 847 848 849