OgreVertexIndexData.cpp 35 KB

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