source: OGRE/trunk/ogrenew/OgreMain/src/OgreVertexIndexData.cpp @ 692

Revision 692, 31.5 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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