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-2013 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 #include "OgreVertexIndexData.h" 30 #include "OgreHardwareBufferManager.h" 31 #include "OgreHardwareVertexBuffer.h" 32 #include "OgreHardwareIndexBuffer.h" 33 #include "OgreVector3.h" 34 #include "OgreAxisAlignedBox.h" 35 #include "OgreRoot.h" 36 #include "OgreRenderSystem.h" 37 #include "OgreException.h" 38 39 namespace Ogre { 40 41 //----------------------------------------------------------------------- VertexData(HardwareBufferManagerBase * mgr)42 VertexData::VertexData(HardwareBufferManagerBase* mgr) 43 { 44 mMgr = mgr ? mgr : HardwareBufferManager::getSingletonPtr(); 45 vertexBufferBinding = mMgr->createVertexBufferBinding(); 46 vertexDeclaration = mMgr->createVertexDeclaration(); 47 mDeleteDclBinding = true; 48 vertexCount = 0; 49 vertexStart = 0; 50 hwAnimDataItemsUsed = 0; 51 52 } 53 //--------------------------------------------------------------------- VertexData(VertexDeclaration * dcl,VertexBufferBinding * bind)54 VertexData::VertexData(VertexDeclaration* dcl, VertexBufferBinding* bind) 55 { 56 // this is a fallback rather than actively used 57 mMgr = HardwareBufferManager::getSingletonPtr(); 58 vertexDeclaration = dcl; 59 vertexBufferBinding = bind; 60 mDeleteDclBinding = false; 61 vertexCount = 0; 62 vertexStart = 0; 63 hwAnimDataItemsUsed = 0; 64 } 65 //----------------------------------------------------------------------- ~VertexData()66 VertexData::~VertexData() 67 { 68 if (mDeleteDclBinding) 69 { 70 mMgr->destroyVertexBufferBinding(vertexBufferBinding); 71 mMgr->destroyVertexDeclaration(vertexDeclaration); 72 } 73 } 74 //----------------------------------------------------------------------- clone(bool copyData,HardwareBufferManagerBase * mgr) const75 VertexData* VertexData::clone(bool copyData, HardwareBufferManagerBase* mgr) const 76 { 77 HardwareBufferManagerBase* pManager = mgr ? mgr : mMgr; 78 79 VertexData* dest = OGRE_NEW VertexData(mgr); 80 81 // Copy vertex buffers in turn 82 const VertexBufferBinding::VertexBufferBindingMap& bindings = 83 this->vertexBufferBinding->getBindings(); 84 VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbend; 85 vbend = bindings.end(); 86 for (vbi = bindings.begin(); vbi != vbend; ++vbi) 87 { 88 HardwareVertexBufferSharedPtr srcbuf = vbi->second; 89 HardwareVertexBufferSharedPtr dstBuf; 90 if (copyData) 91 { 92 // create new buffer with the same settings 93 dstBuf = pManager->createVertexBuffer( 94 srcbuf->getVertexSize(), srcbuf->getNumVertices(), srcbuf->getUsage(), 95 srcbuf->hasShadowBuffer()); 96 97 // copy data 98 dstBuf->copyData(*srcbuf, 0, 0, srcbuf->getSizeInBytes(), true); 99 } 100 else 101 { 102 // don't copy, point at existing buffer 103 dstBuf = srcbuf; 104 } 105 106 // Copy binding 107 dest->vertexBufferBinding->setBinding(vbi->first, dstBuf); 108 } 109 110 // Basic vertex info 111 dest->vertexStart = this->vertexStart; 112 dest->vertexCount = this->vertexCount; 113 // Copy elements 114 const VertexDeclaration::VertexElementList elems = 115 this->vertexDeclaration->getElements(); 116 VertexDeclaration::VertexElementList::const_iterator ei, eiend; 117 eiend = elems.end(); 118 for (ei = elems.begin(); ei != eiend; ++ei) 119 { 120 dest->vertexDeclaration->addElement( 121 ei->getSource(), 122 ei->getOffset(), 123 ei->getType(), 124 ei->getSemantic(), 125 ei->getIndex() ); 126 } 127 128 // Copy reference to hardware shadow buffer, no matter whether copy data or not 129 dest->hardwareShadowVolWBuffer = hardwareShadowVolWBuffer; 130 131 // copy anim data 132 dest->hwAnimationDataList = hwAnimationDataList; 133 dest->hwAnimDataItemsUsed = hwAnimDataItemsUsed; 134 135 136 return dest; 137 } 138 //----------------------------------------------------------------------- prepareForShadowVolume(void)139 void VertexData::prepareForShadowVolume(void) 140 { 141 /* NOTE 142 I would dearly, dearly love to just use a 4D position buffer in order to 143 store the extra 'w' value I need to differentiate between extruded and 144 non-extruded sections of the buffer, so that vertex programs could use that. 145 Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not 146 support 4d position vertices in the fixed-function pipeline. If you use them, 147 you just see nothing. Since we can't know whether the application is going to use 148 fixed function or vertex programs, we have to stick to 3d position vertices and 149 store the 'w' in a separate 1D texture coordinate buffer, which is only used 150 when rendering the shadow. 151 */ 152 153 // Upfront, lets check whether we have vertex program capability 154 RenderSystem* rend = Root::getSingleton().getRenderSystem(); 155 bool useVertexPrograms = false; 156 if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) 157 { 158 useVertexPrograms = true; 159 } 160 161 162 // Look for a position element 163 const VertexElement* posElem = vertexDeclaration->findElementBySemantic(VES_POSITION); 164 if (posElem) 165 { 166 size_t v; 167 unsigned short posOldSource = posElem->getSource(); 168 169 HardwareVertexBufferSharedPtr vbuf = vertexBufferBinding->getBuffer(posOldSource); 170 bool wasSharedBuffer = false; 171 // Are there other elements in the buffer except for the position? 172 if (vbuf->getVertexSize() > posElem->getSize()) 173 { 174 // We need to create another buffer to contain the remaining elements 175 // Most drivers don't like gaps in the declaration, and in any case it's waste 176 wasSharedBuffer = true; 177 } 178 HardwareVertexBufferSharedPtr newPosBuffer, newRemainderBuffer; 179 if (wasSharedBuffer) 180 { 181 newRemainderBuffer = vbuf->getManager()->createVertexBuffer( 182 vbuf->getVertexSize() - posElem->getSize(), vbuf->getNumVertices(), vbuf->getUsage(), 183 vbuf->hasShadowBuffer()); 184 } 185 // Allocate new position buffer, will be FLOAT3 and 2x the size 186 size_t oldVertexCount = vbuf->getNumVertices(); 187 size_t newVertexCount = oldVertexCount * 2; 188 newPosBuffer = vbuf->getManager()->createVertexBuffer( 189 VertexElement::getTypeSize(VET_FLOAT3), newVertexCount, vbuf->getUsage(), 190 vbuf->hasShadowBuffer()); 191 192 // Iterate over the old buffer, copying the appropriate elements and initialising the rest 193 float* pSrc; 194 unsigned char *pBaseSrc = static_cast<unsigned char*>( 195 vbuf->lock(HardwareBuffer::HBL_READ_ONLY)); 196 // Point first destination pointer at the start of the new position buffer, 197 // the other one half way along 198 float *pDest = static_cast<float*>(newPosBuffer->lock(HardwareBuffer::HBL_DISCARD)); 199 float* pDest2 = pDest + oldVertexCount * 3; 200 201 // Precalculate any dimensions of vertex areas outside the position 202 size_t prePosVertexSize = 0; 203 unsigned char *pBaseDestRem = 0; 204 if (wasSharedBuffer) 205 { 206 size_t postPosVertexSize, postPosVertexOffset; 207 pBaseDestRem = static_cast<unsigned char*>( 208 newRemainderBuffer->lock(HardwareBuffer::HBL_DISCARD)); 209 prePosVertexSize = posElem->getOffset(); 210 postPosVertexOffset = prePosVertexSize + posElem->getSize(); 211 postPosVertexSize = vbuf->getVertexSize() - postPosVertexOffset; 212 // the 2 separate bits together should be the same size as the remainder buffer vertex 213 assert (newRemainderBuffer->getVertexSize() == prePosVertexSize + postPosVertexSize); 214 215 // Iterate over the vertices 216 for (v = 0; v < oldVertexCount; ++v) 217 { 218 // Copy position, into both buffers 219 posElem->baseVertexPointerToElement(pBaseSrc, &pSrc); 220 *pDest++ = *pDest2++ = *pSrc++; 221 *pDest++ = *pDest2++ = *pSrc++; 222 *pDest++ = *pDest2++ = *pSrc++; 223 224 // now deal with any other elements 225 // Basically we just memcpy the vertex excluding the position 226 if (prePosVertexSize > 0) 227 memcpy(pBaseDestRem, pBaseSrc, prePosVertexSize); 228 if (postPosVertexSize > 0) 229 memcpy(pBaseDestRem + prePosVertexSize, 230 pBaseSrc + postPosVertexOffset, postPosVertexSize); 231 pBaseDestRem += newRemainderBuffer->getVertexSize(); 232 233 pBaseSrc += vbuf->getVertexSize(); 234 235 } // next vertex 236 } 237 else 238 { 239 // Unshared buffer, can block copy the whole thing 240 memcpy(pDest, pBaseSrc, vbuf->getSizeInBytes()); 241 memcpy(pDest2, pBaseSrc, vbuf->getSizeInBytes()); 242 } 243 244 vbuf->unlock(); 245 newPosBuffer->unlock(); 246 if (wasSharedBuffer) 247 newRemainderBuffer->unlock(); 248 249 // At this stage, he original vertex buffer is going to be destroyed 250 // So we should force the deallocation of any temporary copies 251 vbuf->getManager()->_forceReleaseBufferCopies(vbuf); 252 253 if (useVertexPrograms) 254 { 255 // Now it's time to set up the w buffer 256 hardwareShadowVolWBuffer = vbuf->getManager()->createVertexBuffer( 257 sizeof(float), newVertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); 258 // Fill the first half with 1.0, second half with 0.0 259 pDest = static_cast<float*>( 260 hardwareShadowVolWBuffer->lock(HardwareBuffer::HBL_DISCARD)); 261 for (v = 0; v < oldVertexCount; ++v) 262 { 263 *pDest++ = 1.0f; 264 } 265 for (v = 0; v < oldVertexCount; ++v) 266 { 267 *pDest++ = 0.0f; 268 } 269 hardwareShadowVolWBuffer->unlock(); 270 } 271 272 unsigned short newPosBufferSource; 273 if (wasSharedBuffer) 274 { 275 // Get the a new buffer binding index 276 newPosBufferSource= vertexBufferBinding->getNextIndex(); 277 // Re-bind the old index to the remainder buffer 278 vertexBufferBinding->setBinding(posOldSource, newRemainderBuffer); 279 } 280 else 281 { 282 // We can just re-use the same source idex for the new position buffer 283 newPosBufferSource = posOldSource; 284 } 285 // Bind the new position buffer 286 vertexBufferBinding->setBinding(newPosBufferSource, newPosBuffer); 287 288 // Now, alter the vertex declaration to change the position source 289 // and the offsets of elements using the same buffer 290 VertexDeclaration::VertexElementList::const_iterator elemi = 291 vertexDeclaration->getElements().begin(); 292 VertexDeclaration::VertexElementList::const_iterator elemiend = 293 vertexDeclaration->getElements().end(); 294 unsigned short idx; 295 for(idx = 0; elemi != elemiend; ++elemi, ++idx) 296 { 297 if (&(*elemi) == posElem) 298 { 299 // Modify position to point at new position buffer 300 vertexDeclaration->modifyElement( 301 idx, 302 newPosBufferSource, // new source buffer 303 0, // no offset now 304 VET_FLOAT3, 305 VES_POSITION); 306 } 307 else if (wasSharedBuffer && 308 elemi->getSource() == posOldSource && 309 elemi->getOffset() > prePosVertexSize ) 310 { 311 // This element came after position, remove the position's 312 // size 313 vertexDeclaration->modifyElement( 314 idx, 315 posOldSource, // same old source 316 elemi->getOffset() - posElem->getSize(), // less offset now 317 elemi->getType(), 318 elemi->getSemantic(), 319 elemi->getIndex()); 320 321 } 322 323 } 324 325 326 // Note that we don't change vertexCount, because the other buffer(s) are still the same 327 // size after all 328 329 330 } 331 } 332 //----------------------------------------------------------------------- reorganiseBuffers(VertexDeclaration * newDeclaration,const BufferUsageList & bufferUsages,HardwareBufferManagerBase * mgr)333 void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, 334 const BufferUsageList& bufferUsages, HardwareBufferManagerBase* mgr) 335 { 336 HardwareBufferManagerBase* pManager = mgr ? mgr : mMgr; 337 // Firstly, close up any gaps in the buffer sources which might have arisen 338 newDeclaration->closeGapsInSource(); 339 340 // Build up a list of both old and new elements in each buffer 341 unsigned short buf = 0; 342 vector<void*>::type oldBufferLocks; 343 vector<size_t>::type oldBufferVertexSizes; 344 vector<void*>::type newBufferLocks; 345 vector<size_t>::type newBufferVertexSizes; 346 VertexBufferBinding* newBinding = pManager->createVertexBufferBinding(); 347 const VertexBufferBinding::VertexBufferBindingMap& oldBindingMap = vertexBufferBinding->getBindings(); 348 VertexBufferBinding::VertexBufferBindingMap::const_iterator itBinding; 349 350 // Pre-allocate old buffer locks 351 if (!oldBindingMap.empty()) 352 { 353 size_t count = oldBindingMap.rbegin()->first + 1; 354 oldBufferLocks.resize(count); 355 oldBufferVertexSizes.resize(count); 356 } 357 // Lock all the old buffers for reading 358 for (itBinding = oldBindingMap.begin(); itBinding != oldBindingMap.end(); ++itBinding) 359 { 360 assert(itBinding->second->getNumVertices() >= vertexCount); 361 362 oldBufferVertexSizes[itBinding->first] = 363 itBinding->second->getVertexSize(); 364 oldBufferLocks[itBinding->first] = 365 itBinding->second->lock( 366 HardwareBuffer::HBL_READ_ONLY); 367 } 368 369 // Create new buffers and lock all for writing 370 buf = 0; 371 while (!newDeclaration->findElementsBySource(buf).empty()) 372 { 373 size_t vertexSize = newDeclaration->getVertexSize(buf); 374 375 HardwareVertexBufferSharedPtr vbuf = 376 pManager->createVertexBuffer( 377 vertexSize, 378 vertexCount, 379 bufferUsages[buf]); 380 newBinding->setBinding(buf, vbuf); 381 382 newBufferVertexSizes.push_back(vertexSize); 383 newBufferLocks.push_back( 384 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 385 buf++; 386 } 387 388 // Map from new to old elements 389 typedef map<const VertexElement*, const VertexElement*>::type NewToOldElementMap; 390 NewToOldElementMap newToOldElementMap; 391 const VertexDeclaration::VertexElementList& newElemList = newDeclaration->getElements(); 392 VertexDeclaration::VertexElementList::const_iterator ei, eiend; 393 eiend = newElemList.end(); 394 for (ei = newElemList.begin(); ei != eiend; ++ei) 395 { 396 // Find corresponding old element 397 const VertexElement* oldElem = 398 vertexDeclaration->findElementBySemantic( 399 (*ei).getSemantic(), (*ei).getIndex()); 400 if (!oldElem) 401 { 402 // Error, cannot create new elements with this method 403 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 404 "Element not found in old vertex declaration", 405 "VertexData::reorganiseBuffers"); 406 } 407 newToOldElementMap[&(*ei)] = oldElem; 408 } 409 // Now iterate over the new buffers, pulling data out of the old ones 410 // For each vertex 411 for (size_t v = 0; v < vertexCount; ++v) 412 { 413 // For each (new) element 414 for (ei = newElemList.begin(); ei != eiend; ++ei) 415 { 416 const VertexElement* newElem = &(*ei); 417 NewToOldElementMap::iterator noi = newToOldElementMap.find(newElem); 418 const VertexElement* oldElem = noi->second; 419 unsigned short oldBufferNo = oldElem->getSource(); 420 unsigned short newBufferNo = newElem->getSource(); 421 void* pSrcBase = static_cast<void*>( 422 static_cast<unsigned char*>(oldBufferLocks[oldBufferNo]) 423 + v * oldBufferVertexSizes[oldBufferNo]); 424 void* pDstBase = static_cast<void*>( 425 static_cast<unsigned char*>(newBufferLocks[newBufferNo]) 426 + v * newBufferVertexSizes[newBufferNo]); 427 void *pSrc, *pDst; 428 oldElem->baseVertexPointerToElement(pSrcBase, &pSrc); 429 newElem->baseVertexPointerToElement(pDstBase, &pDst); 430 431 memcpy(pDst, pSrc, newElem->getSize()); 432 433 } 434 } 435 436 // Unlock all buffers 437 for (itBinding = oldBindingMap.begin(); itBinding != oldBindingMap.end(); ++itBinding) 438 { 439 itBinding->second->unlock(); 440 } 441 for (buf = 0; buf < newBinding->getBufferCount(); ++buf) 442 { 443 newBinding->getBuffer(buf)->unlock(); 444 } 445 446 // Delete old binding & declaration 447 if (mDeleteDclBinding) 448 { 449 pManager->destroyVertexBufferBinding(vertexBufferBinding); 450 pManager->destroyVertexDeclaration(vertexDeclaration); 451 } 452 453 // Assign new binding and declaration 454 vertexDeclaration = newDeclaration; 455 vertexBufferBinding = newBinding; 456 // after this is complete, new manager should be used 457 mMgr = pManager; 458 mDeleteDclBinding = true; // because we created these through a manager 459 460 } 461 //----------------------------------------------------------------------- reorganiseBuffers(VertexDeclaration * newDeclaration,HardwareBufferManagerBase * mgr)462 void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, HardwareBufferManagerBase* mgr) 463 { 464 // Derive the buffer usages from looking at where the source has come 465 // from 466 BufferUsageList usages; 467 for (unsigned short b = 0; b <= newDeclaration->getMaxSource(); ++b) 468 { 469 VertexDeclaration::VertexElementList destElems = newDeclaration->findElementsBySource(b); 470 // Initialise with most restrictive version 471 // (not really a usable option, but these flags will be removed) 472 HardwareBuffer::Usage final = static_cast<HardwareBuffer::Usage>( 473 HardwareBuffer::HBU_STATIC_WRITE_ONLY | HardwareBuffer::HBU_DISCARDABLE); 474 VertexDeclaration::VertexElementList::iterator v; 475 for (v = destElems.begin(); v != destElems.end(); ++v) 476 { 477 VertexElement& destelem = *v; 478 // get source 479 const VertexElement* srcelem = 480 vertexDeclaration->findElementBySemantic( 481 destelem.getSemantic(), destelem.getIndex()); 482 // get buffer 483 HardwareVertexBufferSharedPtr srcbuf = 484 vertexBufferBinding->getBuffer(srcelem->getSource()); 485 // improve flexibility only 486 if (srcbuf->getUsage() & HardwareBuffer::HBU_DYNAMIC) 487 { 488 // remove static 489 final = static_cast<HardwareBuffer::Usage>( 490 final & ~HardwareBuffer::HBU_STATIC); 491 // add dynamic 492 final = static_cast<HardwareBuffer::Usage>( 493 final | HardwareBuffer::HBU_DYNAMIC); 494 } 495 if (!(srcbuf->getUsage() & HardwareBuffer::HBU_WRITE_ONLY)) 496 { 497 // remove write only 498 final = static_cast<HardwareBuffer::Usage>( 499 final & ~HardwareBuffer::HBU_WRITE_ONLY); 500 } 501 if (!(srcbuf->getUsage() & HardwareBuffer::HBU_DISCARDABLE)) 502 { 503 // remove discardable 504 final = static_cast<HardwareBuffer::Usage>( 505 final & ~HardwareBuffer::HBU_DISCARDABLE); 506 } 507 508 } 509 usages.push_back(final); 510 } 511 // Call specific method 512 reorganiseBuffers(newDeclaration, usages, mgr); 513 514 } 515 //----------------------------------------------------------------------- closeGapsInBindings(void)516 void VertexData::closeGapsInBindings(void) 517 { 518 if (!vertexBufferBinding->hasGaps()) 519 return; 520 521 // Check for error first 522 const VertexDeclaration::VertexElementList& allelems = 523 vertexDeclaration->getElements(); 524 VertexDeclaration::VertexElementList::const_iterator ai; 525 for (ai = allelems.begin(); ai != allelems.end(); ++ai) 526 { 527 const VertexElement& elem = *ai; 528 if (!vertexBufferBinding->isBufferBound(elem.getSource())) 529 { 530 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 531 "No buffer is bound to that element source.", 532 "VertexData::closeGapsInBindings"); 533 } 534 } 535 536 // Close gaps in the vertex buffer bindings 537 VertexBufferBinding::BindingIndexMap bindingIndexMap; 538 vertexBufferBinding->closeGaps(bindingIndexMap); 539 540 // Modify vertex elements to reference to new buffer index 541 unsigned short elemIndex = 0; 542 for (ai = allelems.begin(); ai != allelems.end(); ++ai, ++elemIndex) 543 { 544 const VertexElement& elem = *ai; 545 VertexBufferBinding::BindingIndexMap::const_iterator it = 546 bindingIndexMap.find(elem.getSource()); 547 assert(it != bindingIndexMap.end()); 548 ushort targetSource = it->second; 549 if (elem.getSource() != targetSource) 550 { 551 vertexDeclaration->modifyElement(elemIndex, 552 targetSource, elem.getOffset(), elem.getType(), 553 elem.getSemantic(), elem.getIndex()); 554 } 555 } 556 } 557 //----------------------------------------------------------------------- removeUnusedBuffers(void)558 void VertexData::removeUnusedBuffers(void) 559 { 560 set<ushort>::type usedBuffers; 561 562 // Collect used buffers 563 const VertexDeclaration::VertexElementList& allelems = 564 vertexDeclaration->getElements(); 565 VertexDeclaration::VertexElementList::const_iterator ai; 566 for (ai = allelems.begin(); ai != allelems.end(); ++ai) 567 { 568 const VertexElement& elem = *ai; 569 usedBuffers.insert(elem.getSource()); 570 } 571 572 // Unset unused buffer bindings 573 ushort count = vertexBufferBinding->getLastBoundIndex(); 574 for (ushort index = 0; index < count; ++index) 575 { 576 if (usedBuffers.find(index) == usedBuffers.end() && 577 vertexBufferBinding->isBufferBound(index)) 578 { 579 vertexBufferBinding->unsetBinding(index); 580 } 581 } 582 583 // Close gaps 584 closeGapsInBindings(); 585 } 586 //----------------------------------------------------------------------- convertPackedColour(VertexElementType srcType,VertexElementType destType)587 void VertexData::convertPackedColour( 588 VertexElementType srcType, VertexElementType destType) 589 { 590 if (destType != VET_COLOUR_ABGR && destType != VET_COLOUR_ARGB) 591 { 592 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 593 "Invalid destType parameter", "VertexData::convertPackedColour"); 594 } 595 if (srcType != VET_COLOUR_ABGR && srcType != VET_COLOUR_ARGB) 596 { 597 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 598 "Invalid srcType parameter", "VertexData::convertPackedColour"); 599 } 600 601 const VertexBufferBinding::VertexBufferBindingMap& bindMap = 602 vertexBufferBinding->getBindings(); 603 VertexBufferBinding::VertexBufferBindingMap::const_iterator bindi; 604 for (bindi = bindMap.begin(); bindi != bindMap.end(); ++bindi) 605 { 606 VertexDeclaration::VertexElementList elems = 607 vertexDeclaration->findElementsBySource(bindi->first); 608 bool conversionNeeded = false; 609 VertexDeclaration::VertexElementList::iterator elemi; 610 for (elemi = elems.begin(); elemi != elems.end(); ++elemi) 611 { 612 VertexElement& elem = *elemi; 613 if (elem.getType() == VET_COLOUR || 614 ((elem.getType() == VET_COLOUR_ABGR || elem.getType() == VET_COLOUR_ARGB) 615 && elem.getType() != destType)) 616 { 617 conversionNeeded = true; 618 } 619 } 620 621 if (conversionNeeded) 622 { 623 void* pBase = bindi->second->lock(HardwareBuffer::HBL_NORMAL); 624 625 for (size_t v = 0; v < bindi->second->getNumVertices(); ++v) 626 { 627 628 for (elemi = elems.begin(); elemi != elems.end(); ++elemi) 629 { 630 VertexElement& elem = *elemi; 631 VertexElementType currType = (elem.getType() == VET_COLOUR) ? 632 srcType : elem.getType(); 633 if (elem.getType() == VET_COLOUR || 634 ((elem.getType() == VET_COLOUR_ABGR || elem.getType() == VET_COLOUR_ARGB) 635 && elem.getType() != destType)) 636 { 637 uint32* pRGBA; 638 elem.baseVertexPointerToElement(pBase, &pRGBA); 639 VertexElement::convertColourValue(currType, destType, pRGBA); 640 } 641 } 642 pBase = static_cast<void*>( 643 static_cast<char*>(pBase) + bindi->second->getVertexSize()); 644 } 645 bindi->second->unlock(); 646 647 // Modify the elements to reflect the changed type 648 const VertexDeclaration::VertexElementList& allelems = 649 vertexDeclaration->getElements(); 650 VertexDeclaration::VertexElementList::const_iterator ai; 651 unsigned short elemIndex = 0; 652 for (ai = allelems.begin(); ai != allelems.end(); ++ai, ++elemIndex) 653 { 654 const VertexElement& elem = *ai; 655 if (elem.getType() == VET_COLOUR || 656 ((elem.getType() == VET_COLOUR_ABGR || elem.getType() == VET_COLOUR_ARGB) 657 && elem.getType() != destType)) 658 { 659 vertexDeclaration->modifyElement(elemIndex, 660 elem.getSource(), elem.getOffset(), destType, 661 elem.getSemantic(), elem.getIndex()); 662 } 663 } 664 665 } 666 667 668 } // each buffer 669 670 671 } 672 //----------------------------------------------------------------------- allocateHardwareAnimationElements(ushort count,bool animateNormals)673 ushort VertexData::allocateHardwareAnimationElements(ushort count, bool animateNormals) 674 { 675 // Find first free texture coord set 676 unsigned short texCoord = vertexDeclaration->getNextFreeTextureCoordinate(); 677 unsigned short freeCount = (ushort)(OGRE_MAX_TEXTURE_COORD_SETS - texCoord); 678 if (animateNormals) 679 // we need 2x the texture coords, round down 680 freeCount /= 2; 681 682 unsigned short supportedCount = std::min(freeCount, count); 683 684 // Increase to correct size 685 for (size_t c = hwAnimationDataList.size(); c < supportedCount; ++c) 686 { 687 // Create a new 3D texture coordinate set 688 HardwareAnimationData data; 689 data.targetBufferIndex = vertexBufferBinding->getNextIndex(); 690 vertexDeclaration->addElement(data.targetBufferIndex, 0, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoord++); 691 if (animateNormals) 692 vertexDeclaration->addElement(data.targetBufferIndex, sizeof(float)*3, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoord++); 693 694 hwAnimationDataList.push_back(data); 695 // Vertex buffer will not be bound yet, we expect this to be done by the 696 // caller when it becomes appropriate (e.g. through a VertexAnimationTrack) 697 } 698 699 return supportedCount; 700 } 701 //----------------------------------------------------------------------- 702 //----------------------------------------------------------------------- IndexData()703 IndexData::IndexData() 704 { 705 indexCount = 0; 706 indexStart = 0; 707 708 } 709 //----------------------------------------------------------------------- ~IndexData()710 IndexData::~IndexData() 711 { 712 } 713 //----------------------------------------------------------------------- clone(bool copyData,HardwareBufferManagerBase * mgr) const714 IndexData* IndexData::clone(bool copyData, HardwareBufferManagerBase* mgr) const 715 { 716 HardwareBufferManagerBase* pManager = mgr ? mgr : HardwareBufferManager::getSingletonPtr(); 717 IndexData* dest = OGRE_NEW IndexData(); 718 if (indexBuffer.get()) 719 { 720 if (copyData) 721 { 722 dest->indexBuffer = pManager->createIndexBuffer(indexBuffer->getType(), indexBuffer->getNumIndexes(), 723 indexBuffer->getUsage(), indexBuffer->hasShadowBuffer()); 724 dest->indexBuffer->copyData(*indexBuffer, 0, 0, indexBuffer->getSizeInBytes(), true); 725 } 726 else 727 { 728 dest->indexBuffer = indexBuffer; 729 } 730 } 731 dest->indexCount = indexCount; 732 dest->indexStart = indexStart; 733 return dest; 734 } 735 //----------------------------------------------------------------------- 736 //----------------------------------------------------------------------- 737 // Local Utility class for vertex cache optimizer 738 class Triangle 739 { 740 public: 741 enum EdgeMatchType { 742 AB, BC, CA, ANY, NONE 743 }; 744 745 uint32 a, b, c; 746 Triangle()747 inline Triangle() 748 { 749 } 750 Triangle(uint32 ta,uint32 tb,uint32 tc)751 inline Triangle( uint32 ta, uint32 tb, uint32 tc ) 752 : a( ta ), b( tb ), c( tc ) 753 { 754 } 755 Triangle(uint32 t[3])756 inline Triangle( uint32 t[3] ) 757 : a( t[0] ), b( t[1] ), c( t[2] ) 758 { 759 } 760 Triangle(const Triangle & t)761 inline Triangle( const Triangle& t ) 762 : a( t.a ), b( t.b ), c( t.c ) 763 { 764 } 765 sharesEdge(const Triangle & t) const766 inline bool sharesEdge(const Triangle& t) const 767 { 768 return( (a == t.a && b == t.c) || 769 (a == t.b && b == t.a) || 770 (a == t.c && b == t.b) || 771 (b == t.a && c == t.c) || 772 (b == t.b && c == t.a) || 773 (b == t.c && c == t.b) || 774 (c == t.a && a == t.c) || 775 (c == t.b && a == t.a) || 776 (c == t.c && a == t.b) ); 777 } 778 sharesEdge(const uint32 ea,const uint32 eb,const Triangle & t) const779 inline bool sharesEdge(const uint32 ea, const uint32 eb, const Triangle& t) const 780 { 781 return( (ea == t.a && eb == t.c) || 782 (ea == t.b && eb == t.a) || 783 (ea == t.c && eb == t.b) ); 784 } 785 sharesEdge(const EdgeMatchType edge,const Triangle & t) const786 inline bool sharesEdge(const EdgeMatchType edge, const Triangle& t) const 787 { 788 if (edge == AB) 789 return sharesEdge(a, b, t); 790 else if (edge == BC) 791 return sharesEdge(b, c, t); 792 else if (edge == CA) 793 return sharesEdge(c, a, t); 794 else 795 return (edge == ANY) == sharesEdge(t); 796 } 797 endoSharedEdge(const Triangle & t) const798 inline EdgeMatchType endoSharedEdge(const Triangle& t) const 799 { 800 if (sharesEdge(a, b, t)) return AB; 801 if (sharesEdge(b, c, t)) return BC; 802 if (sharesEdge(c, a, t)) return CA; 803 return NONE; 804 } 805 exoSharedEdge(const Triangle & t) const806 inline EdgeMatchType exoSharedEdge(const Triangle& t) const 807 { 808 return t.endoSharedEdge(*this); 809 } 810 shiftClockwise()811 inline void shiftClockwise() 812 { 813 uint32 t = a; 814 a = c; 815 c = b; 816 b = t; 817 } 818 shiftCounterClockwise()819 inline void shiftCounterClockwise() 820 { 821 uint32 t = a; 822 a = b; 823 b = c; 824 c = t; 825 } 826 }; 827 //----------------------------------------------------------------------- 828 //----------------------------------------------------------------------- optimiseVertexCacheTriList(void)829 void IndexData::optimiseVertexCacheTriList(void) 830 { 831 if (indexBuffer->isLocked()) return; 832 833 void *buffer = indexBuffer->lock(HardwareBuffer::HBL_NORMAL); 834 835 Triangle* triangles; 836 837 size_t nIndexes = indexCount; 838 size_t nTriangles = nIndexes / 3; 839 size_t i, j; 840 uint16 *source = 0; 841 842 if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT) 843 { 844 triangles = OGRE_ALLOC_T(Triangle, nTriangles, MEMCATEGORY_GEOMETRY); 845 source = (uint16 *)buffer; 846 uint32 *dest = (uint32 *)triangles; 847 for (i = 0; i < nIndexes; ++i) dest[i] = source[i]; 848 } 849 else 850 triangles = static_cast<Triangle*>(buffer); 851 852 // sort triangles based on shared edges 853 uint32 *destlist = OGRE_ALLOC_T(uint32, nTriangles, MEMCATEGORY_GEOMETRY); 854 unsigned char *visited = OGRE_ALLOC_T(unsigned char, nTriangles, MEMCATEGORY_GEOMETRY); 855 856 for (i = 0; i < nTriangles; ++i) visited[i] = 0; 857 858 uint32 start = 0, ti = 0, destcount = 0; 859 860 bool found = false; 861 for (i = 0; i < nTriangles; ++i) 862 { 863 if (found) 864 found = false; 865 else 866 { 867 while (visited[start++]); 868 ti = start - 1; 869 } 870 871 destlist[destcount++] = ti; 872 visited[ti] = 1; 873 874 for (j = start; j < nTriangles; ++j) 875 { 876 if (visited[j]) continue; 877 878 if (triangles[ti].sharesEdge(triangles[j])) 879 { 880 found = true; 881 ti = static_cast<uint32>(j); 882 break; 883 } 884 } 885 } 886 887 if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT) 888 { 889 // reorder the indexbuffer 890 j = 0; 891 for (i = 0; i < nTriangles; ++i) 892 { 893 Triangle *t = &triangles[destlist[i]]; 894 if(source) 895 { 896 source[j++] = (uint16)t->a; 897 source[j++] = (uint16)t->b; 898 source[j++] = (uint16)t->c; 899 } 900 } 901 OGRE_FREE(triangles, MEMCATEGORY_GEOMETRY); 902 } 903 else 904 { 905 uint32 *reflist = OGRE_ALLOC_T(uint32, nTriangles, MEMCATEGORY_GEOMETRY); 906 907 // fill the referencebuffer 908 for (i = 0; i < nTriangles; ++i) 909 reflist[destlist[i]] = static_cast<uint32>(i); 910 911 // reorder the indexbuffer 912 for (i = 0; i < nTriangles; ++i) 913 { 914 j = destlist[i]; 915 if (i == j) continue; // do not move triangle 916 917 // swap triangles 918 919 Triangle t = triangles[i]; 920 triangles[i] = triangles[j]; 921 triangles[j] = t; 922 923 // change reference 924 destlist[reflist[i]] = static_cast<uint32>(j); 925 // destlist[i] = i; // not needed, it will not be used 926 } 927 928 OGRE_FREE(reflist, MEMCATEGORY_GEOMETRY); 929 } 930 931 OGRE_FREE(destlist, MEMCATEGORY_GEOMETRY); 932 OGRE_FREE(visited, MEMCATEGORY_GEOMETRY); 933 934 indexBuffer->unlock(); 935 } 936 //----------------------------------------------------------------------- 937 //----------------------------------------------------------------------- profile(const HardwareIndexBufferSharedPtr & indexBuffer)938 void VertexCacheProfiler::profile(const HardwareIndexBufferSharedPtr& indexBuffer) 939 { 940 if (indexBuffer->isLocked()) return; 941 942 uint16 *shortbuffer = (uint16 *)indexBuffer->lock(HardwareBuffer::HBL_READ_ONLY); 943 944 if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT) 945 for (unsigned int i = 0; i < indexBuffer->getNumIndexes(); ++i) 946 inCache(shortbuffer[i]); 947 else 948 { 949 uint32 *buffer = (uint32 *)shortbuffer; 950 for (unsigned int i = 0; i < indexBuffer->getNumIndexes(); ++i) 951 inCache(buffer[i]); 952 } 953 954 indexBuffer->unlock(); 955 } 956 957 //----------------------------------------------------------------------- inCache(unsigned int index)958 bool VertexCacheProfiler::inCache(unsigned int index) 959 { 960 for (unsigned int i = 0; i < buffersize; ++i) 961 { 962 if (index == cache[i]) 963 { 964 hit++; 965 return true; 966 } 967 } 968 969 miss++; 970 cache[tail++] = index; 971 tail %= size; 972 973 if (buffersize < size) buffersize++; 974 975 return false; 976 } 977 978 979 } 980