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