Coverage Report

Created: 2026-09-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreVertexIndexData.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
#include "OgreVertexIndexData.h"
30
#include "OgreHardwareVertexBuffer.h"
31
32
0
#define INT10_MAX ((1 << 9) - 1)
33
34
namespace Ogre {
35
    static void swapPackedRB(uint32* ptr)
36
0
    {
37
0
        auto cptr = (uint8*)ptr;
38
0
        std::swap(cptr[0], cptr[2]);
39
0
    }
40
41
    struct int_10_10_10_2
42
    {
43
        int32_t x : 10;
44
        int32_t y : 10;
45
        int32_t z : 10;
46
        int32_t w :  2;
47
    };
48
49
    template<int INCLUDE_W>
50
    static void pack_10_10_10_2(uint8* pDst, uint8* pSrc, int elemOffset)
51
0
    {
52
0
        float* pFloat = (float*)(pSrc + elemOffset);
53
0
        int_10_10_10_2 packed = {int(INT10_MAX * pFloat[0]), int(INT10_MAX * pFloat[1]), int(INT10_MAX * pFloat[2]), 1};
54
0
        if(INCLUDE_W)
55
0
            packed.w = int(pFloat[3]);
56
0
        memcpy(pDst + elemOffset, &packed, sizeof(int_10_10_10_2));
57
0
    }
Unexecuted instantiation: OgreVertexIndexData.cpp:void Ogre::pack_10_10_10_2<0>(unsigned char*, unsigned char*, int)
Unexecuted instantiation: OgreVertexIndexData.cpp:void Ogre::pack_10_10_10_2<1>(unsigned char*, unsigned char*, int)
58
59
    template<int INCLUDE_W>
60
    static void unpack_10_10_10_2(uint8* pDst, uint8* pSrc, int elemOffset)
61
0
    {
62
0
        int_10_10_10_2* pPacked = (int_10_10_10_2*)(pSrc + elemOffset);
63
0
        float* pFloat = (float*)(pDst + elemOffset);
64
65
0
        pFloat[0] = float(pPacked->x) / INT10_MAX;
66
0
        pFloat[1] = float(pPacked->y) / INT10_MAX;
67
0
        pFloat[2] = float(pPacked->z) / INT10_MAX;
68
0
        if(INCLUDE_W)
69
0
            pFloat[3] = pPacked->w;
70
0
    }
Unexecuted instantiation: OgreVertexIndexData.cpp:void Ogre::unpack_10_10_10_2<0>(unsigned char*, unsigned char*, int)
Unexecuted instantiation: OgreVertexIndexData.cpp:void Ogre::unpack_10_10_10_2<1>(unsigned char*, unsigned char*, int)
71
72
    static void extract_float3(uint8* pDst, uint8* pSrc, int elemOffset)
73
0
    {
74
0
        memcpy(pDst, pSrc + elemOffset, sizeof(float) * 3);
75
0
    }
76
77
    static void pad_16x3(uint8* pDst, uint8* pSrc, int elemOffset)
78
0
    {
79
        // for half3, we want 1.0 in the 4th component
80
        // for others we dont care, so do it unconditionally
81
0
        static const uint16 one16f = Bitwise::floatToHalf(1.0f);
82
0
        memcpy(pDst + elemOffset, pSrc + elemOffset, sizeof(uint16) * 3);
83
0
        memcpy(pDst + elemOffset + sizeof(uint16) * 3, &one16f, sizeof(uint16));
84
0
    }
85
86
    static void float_to_half_3(uint8* pDst, uint8* pSrc, int elemOffset)
87
0
    {
88
0
        float* pFloat = (float*)(pSrc + elemOffset);
89
0
        uint16* pHalf = (uint16*)(pDst + elemOffset);
90
0
        pHalf[0] = Bitwise::floatToHalf(pFloat[0]);
91
0
        pHalf[1] = Bitwise::floatToHalf(pFloat[1]);
92
0
        pHalf[2] = Bitwise::floatToHalf(pFloat[2]);
93
0
    }
94
95
    /** Splice out an element from a vertex buffer
96
     * @param elem The element to splice out of the vertex
97
     * @param srcBuf Source buffer
98
     * @param pDst Destination buffer for the vertex without the element
99
     * @param pElemDst Destination buffer for the element (can be the same as pDst)
100
     */
101
    static void spliceElement(const VertexElement* elem, const HardwareVertexBufferPtr& srcBuf, uint8* pDst,
102
                              uint8* pElemDst, uint32 newElemSize, void (*elemConvert)(uint8*, uint8*, int))
103
0
    {
104
0
        auto vertexSize = srcBuf->getVertexSize();
105
0
        auto numVerts = srcBuf->getNumVertices();
106
107
0
        auto elemSize = elem->getSize();
108
0
        int elemOffset = elem->getOffset();
109
110
0
        auto postVertexOffset = elemOffset + elemSize;
111
0
        auto postVertexSize = vertexSize - postVertexOffset;
112
113
0
        auto elemDstSize = pDst == pElemDst ? newElemSize : 0;
114
0
        size_t newVertexSize = vertexSize - elemSize + elemDstSize;
115
0
        auto elemDstStep = pDst == pElemDst ? newVertexSize : newElemSize;
116
117
0
        HardwareBufferLockGuard srcLock(srcBuf, HardwareBuffer::HBL_READ_ONLY);
118
0
        uint8* pSrc = static_cast<uint8*>(srcLock.pData);
119
120
0
        for (uint32 v = 0; v < numVerts; ++v)
121
0
        {
122
            // copy and convert element from vertex
123
0
            elemConvert(pElemDst, pSrc, elemOffset);
124
0
            pElemDst += elemDstStep;
125
126
            // copy over other data
127
0
            if (elemOffset)
128
0
                memcpy(pDst, pSrc, elemOffset);
129
0
            if (postVertexSize)
130
0
                memcpy(pDst + elemOffset + elemDstSize, pSrc + postVertexOffset, postVertexSize);
131
132
0
            pSrc += vertexSize;
133
0
            pDst += newVertexSize;
134
0
        }
135
0
    }
136
137
    static void updateVertexDeclaration(VertexDeclaration* decl, const VertexElement* elem, VertexElementType newType, uint16 newSource)
138
0
    {
139
0
        auto elemSize = elem->getSize();
140
0
        auto oldElemOffset = elem->getOffset();
141
0
        auto newElemOffset = oldElemOffset;
142
143
0
        auto newElemSize = VertexElement::getTypeSize(newType);
144
0
        auto oldSource = elem->getSource();
145
146
0
        if(newSource != oldSource)
147
0
        {
148
0
            newElemOffset = 0;
149
0
            newElemSize = 0;
150
0
        }
151
152
0
        uint16 idx = 0;
153
0
        for (const auto& e : decl->getElements())
154
0
        {
155
0
            if (&e == elem)
156
0
            {
157
                // Modify element
158
0
                decl->modifyElement(idx, newSource, newElemOffset, newType, elem->getSemantic(), elem->getIndex());
159
0
            }
160
0
            else if (e.getSource() == oldSource && e.getOffset() > oldElemOffset)
161
0
            {
162
                // shift elements after this one
163
0
                decl->modifyElement(idx, e.getSource(), e.getOffset() - elemSize + newElemSize, e.getType(),
164
0
                                    e.getSemantic(), e.getIndex());
165
0
            }
166
0
            idx++;
167
0
        }
168
0
    }
169
170
    //-----------------------------------------------------------------------
171
    VertexData::VertexData(HardwareBufferManagerBase* mgr)
172
0
    {
173
0
        mMgr = mgr ? mgr : HardwareBufferManager::getSingletonPtr();
174
0
        vertexBufferBinding = mMgr->createVertexBufferBinding();
175
0
        vertexDeclaration = mMgr->createVertexDeclaration();
176
0
        mDeleteDclBinding = true;
177
0
        vertexCount = 0;
178
0
        vertexStart = 0;
179
0
        hwAnimDataItemsUsed = 0;
180
181
0
    }
182
    //---------------------------------------------------------------------
183
    VertexData::VertexData(VertexDeclaration* dcl, VertexBufferBinding* bind)
184
0
    {
185
        // this is a fallback rather than actively used
186
0
        mMgr = HardwareBufferManager::getSingletonPtr();
187
0
        vertexDeclaration = dcl;
188
0
        vertexBufferBinding = bind;
189
0
        mDeleteDclBinding = false;
190
0
        vertexCount = 0;
191
0
        vertexStart = 0;
192
0
        hwAnimDataItemsUsed = 0;
193
0
    }
194
    //-----------------------------------------------------------------------
195
    VertexData::~VertexData()
196
0
    {
197
0
        if (mDeleteDclBinding)
198
0
        {
199
0
            mMgr->destroyVertexBufferBinding(vertexBufferBinding);
200
0
            mMgr->destroyVertexDeclaration(vertexDeclaration);
201
0
        }
202
0
    }
203
    //-----------------------------------------------------------------------
204
    VertexData* VertexData::clone(bool copyData, HardwareBufferManagerBase* mgr) const
205
0
    {
206
0
        HardwareBufferManagerBase* pManager = mgr ? mgr : mMgr;
207
208
0
        VertexData* dest = OGRE_NEW VertexData(mgr);
209
210
        // Copy vertex buffers in turn
211
0
        const VertexBufferBinding::VertexBufferBindingMap& bindings = 
212
0
            this->vertexBufferBinding->getBindings();
213
0
        VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbend;
214
0
        vbend = bindings.end();
215
0
        for (vbi = bindings.begin(); vbi != vbend; ++vbi)
216
0
        {
217
0
            HardwareVertexBufferSharedPtr srcbuf = vbi->second;
218
0
            HardwareVertexBufferSharedPtr dstBuf;
219
0
            if (copyData)
220
0
            {
221
                // create new buffer with the same settings
222
0
                dstBuf = pManager->createVertexBuffer(
223
0
                        srcbuf->getVertexSize(), srcbuf->getNumVertices(), srcbuf->getUsage(),
224
0
                        srcbuf->hasShadowBuffer());
225
226
                // copy data
227
0
                dstBuf->copyData(*srcbuf, 0, 0, srcbuf->getSizeInBytes(), true);
228
0
            }
229
0
            else
230
0
            {
231
                // don't copy, point at existing buffer
232
0
                dstBuf = srcbuf;
233
0
            }
234
235
            // Copy binding
236
0
            dest->vertexBufferBinding->setBinding(vbi->first, dstBuf);
237
0
        }
238
239
        // Basic vertex info
240
0
        dest->vertexStart = this->vertexStart;
241
0
        dest->vertexCount = this->vertexCount;
242
        // Copy elements
243
0
        const VertexDeclaration::VertexElementList elems = 
244
0
            this->vertexDeclaration->getElements();
245
0
        VertexDeclaration::VertexElementList::const_iterator ei, eiend;
246
0
        eiend = elems.end();
247
0
        for (ei = elems.begin(); ei != eiend; ++ei)
248
0
        {
249
0
            dest->vertexDeclaration->addElement(
250
0
                ei->getSource(),
251
0
                ei->getOffset(),
252
0
                ei->getType(),
253
0
                ei->getSemantic(),
254
0
                ei->getIndex() );
255
0
        }
256
257
        // Copy reference to hardware shadow buffer, no matter whether copy data or not
258
0
        dest->hardwareShadowVolWBuffer = hardwareShadowVolWBuffer;
259
260
        // copy anim data
261
0
        dest->hwAnimationDataList = hwAnimationDataList;
262
0
        dest->hwAnimDataItemsUsed = hwAnimDataItemsUsed;
263
264
        
265
0
        return dest;
266
0
    }
267
268
    void VertexData::convertVertexElement(VertexElementSemantic semantic, VertexElementType dstType, uint16 index)
269
0
    {
270
0
        auto elem = vertexDeclaration->findElementBySemantic(semantic, index);
271
272
0
        if(!elem)
273
0
            return; // nothing to do
274
275
0
        auto srcBaseType = VertexElement::getBaseType(elem->getType());
276
0
        if (srcBaseType == VET_FLOAT1 && srcBaseType == VertexElement::getBaseType(dstType))
277
0
            return; // silently ignore floatX > floatY conversions
278
279
0
        auto srcType = elem->getType();
280
0
        auto vbuf = vertexBufferBinding->getBuffer(elem->getSource());
281
282
0
        uint32 newElemSize = VertexElement::getTypeSize(dstType);
283
0
        size_t newVertexSize = vbuf->getVertexSize() - elem->getSize() + newElemSize;
284
0
        auto newVBuf = vbuf->getManager()->createVertexBuffer(newVertexSize, vbuf->getNumVertices(), vbuf->getUsage(),
285
0
                                                              vbuf->hasShadowBuffer());
286
287
0
        {
288
0
            HardwareBufferLockGuard dst(newVBuf, HardwareBuffer::HBL_DISCARD);
289
0
            auto pDst = static_cast<uint8*>(dst.pData);
290
291
0
            if(dstType == VET_INT_10_10_10_2_NORM)
292
0
            {
293
0
                if(srcType == VET_FLOAT3)
294
0
                    spliceElement(elem, vbuf, pDst, pDst, newElemSize, pack_10_10_10_2<false>);
295
0
                else
296
0
                {
297
0
                    OgreAssert(srcType == VET_FLOAT4, "unsupported conversion");
298
0
                    spliceElement(elem, vbuf, pDst, pDst, newElemSize, pack_10_10_10_2<true>);
299
0
                }
300
0
            }
301
0
            else if(dstType == VET_FLOAT3)
302
0
            {
303
0
                OgreAssert(srcType == VET_INT_10_10_10_2_NORM, "unsupported conversion");
304
0
                spliceElement(elem, vbuf, pDst, pDst, newElemSize, unpack_10_10_10_2<false>);
305
0
            }
306
0
            else if(dstType == VET_FLOAT4)
307
0
            {
308
0
                OgreAssert(srcType == VET_INT_10_10_10_2_NORM, "unsupported conversion");
309
0
                spliceElement(elem, vbuf, pDst, pDst, newElemSize, unpack_10_10_10_2<true>);
310
0
            }
311
0
            else if(dstType == VET_HALF3)
312
0
            {
313
0
                OgreAssert(srcType == VET_FLOAT3, "unsupported conversion");
314
0
                spliceElement(elem, vbuf, pDst, pDst, newElemSize, float_to_half_3);
315
0
            }
316
0
            else if(dstType == VET_HALF4 || dstType == VET_SHORT4 || dstType == VET_USHORT4)
317
0
            {
318
                // pad 16x3 formats to 16x4
319
0
                OgreAssert(srcType == VET_HALF3 || srcType == VET_SHORT3 || srcType == VET_USHORT3, "unsupported conversion");
320
0
                spliceElement(elem, vbuf, pDst, pDst, newElemSize, pad_16x3);
321
0
            }
322
0
            else
323
0
            {
324
0
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "unsupported dstType");
325
0
            }
326
0
        }
327
328
        // Bind the new buffer
329
0
        vertexBufferBinding->setBinding(elem->getSource(), newVBuf);
330
0
        updateVertexDeclaration(vertexDeclaration, elem, dstType, elem->getSource());
331
0
    }
332
    //-----------------------------------------------------------------------
333
    void VertexData::prepareForShadowVolume(void)
334
0
    {
335
        /* NOTE
336
        I would dearly, dearly love to just use a 4D position buffer in order to 
337
        store the extra 'w' value I need to differentiate between extruded and 
338
        non-extruded sections of the buffer, so that vertex programs could use that.
339
        Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not
340
        support 4d position vertices in the fixed-function pipeline. If you use them, 
341
        you just see nothing. Since we can't know whether the application is going to use
342
        fixed function or vertex programs, we have to stick to 3d position vertices and
343
        store the 'w' in a separate 1D texture coordinate buffer, which is only used
344
        when rendering the shadow.
345
        */
346
347
        // Look for a position element
348
0
        const VertexElement* posElem = vertexDeclaration->findElementBySemantic(VES_POSITION);
349
0
        if (!posElem)
350
0
            return;
351
352
        // Upfront, lets check whether we have vertex program capability
353
0
        bool useVertexPrograms = Root::getSingleton().getRenderSystem() != 0;
354
355
0
        auto vbuf = vertexBufferBinding->getBuffer(posElem->getSource());
356
357
        // Are there other elements in the buffer except for the position?
358
        // We need to create another buffer to contain the remaining elements
359
        // Most drivers don't like gaps in the declaration, and in any case it's waste
360
0
        HardwareVertexBufferPtr newRemainderBuffer;
361
0
        if (vbuf->getVertexSize() > posElem->getSize())
362
0
        {
363
0
            newRemainderBuffer = vbuf->getManager()->createVertexBuffer(
364
0
                vbuf->getVertexSize() - posElem->getSize(), vbuf->getNumVertices(), vbuf->getUsage(),
365
0
                vbuf->hasShadowBuffer());
366
0
        }
367
        // Allocate new position buffer, will be FLOAT3 and 2x the size
368
0
        size_t oldVertexCount = vbuf->getNumVertices();
369
0
        size_t newVertexCount = oldVertexCount * 2;
370
0
        auto newPosBuffer = vbuf->getManager()->createVertexBuffer(
371
0
            VertexElement::getTypeSize(VET_FLOAT3), newVertexCount, vbuf->getUsage(), vbuf->hasShadowBuffer());
372
373
        // Point first destination pointer at the start of the new position buffer,
374
        // the other one half way along
375
0
        auto pDest = static_cast<float*>(newPosBuffer->lock(HardwareBuffer::HBL_DISCARD));
376
0
        auto pDest2 = pDest + oldVertexCount * 3;
377
378
0
        if (newRemainderBuffer)
379
0
        {
380
            // Basically we just memcpy the vertex excluding the position
381
0
            HardwareBufferLockGuard destRemLock(newRemainderBuffer, HardwareBuffer::HBL_DISCARD);
382
0
            spliceElement(posElem, vbuf, (uint8*)destRemLock.pData, (uint8*)pDest, posElem->getSize(), extract_float3);
383
0
        }
384
0
        else
385
0
        {
386
            // Unshared buffer, can block copy the whole thing
387
0
            vbuf->readData(0, vbuf->getSizeInBytes(), pDest);
388
0
        }
389
390
0
        memcpy(pDest2, pDest, oldVertexCount * 3 * sizeof(float));
391
392
0
        newPosBuffer->unlock();
393
394
        // At this stage, he original vertex buffer is going to be destroyed
395
        // So we should force the deallocation of any temporary copies
396
0
        vbuf->getManager()->_forceReleaseBufferCopies(vbuf);
397
398
0
        if (useVertexPrograms)
399
0
        {
400
            // Now it's time to set up the w buffer
401
0
            hardwareShadowVolWBuffer =
402
0
                vbuf->getManager()->createVertexBuffer(sizeof(float), newVertexCount, HBU_GPU_ONLY, false);
403
            // Fill the first half with 1.0, second half with 0.0
404
0
            pDest = static_cast<float*>(hardwareShadowVolWBuffer->lock(HardwareBuffer::HBL_DISCARD));
405
0
            for (size_t v = 0; v < oldVertexCount; ++v)
406
0
            {
407
0
                *pDest++ = 1.0f;
408
0
            }
409
            // Fill the second half with 0.0
410
0
            memset(pDest, 0, sizeof(float) * oldVertexCount);
411
0
            hardwareShadowVolWBuffer->unlock();
412
0
        }
413
414
0
        auto newPosBufferSource = posElem->getSource();
415
0
        if (newRemainderBuffer)
416
0
        {
417
            // Get the a new buffer binding index
418
0
            newPosBufferSource= vertexBufferBinding->getNextIndex();
419
            // Re-bind the old index to the remainder buffer
420
0
            vertexBufferBinding->setBinding(posElem->getSource(), newRemainderBuffer);
421
0
        }
422
423
        // Bind the new position buffer
424
0
        vertexBufferBinding->setBinding(newPosBufferSource, newPosBuffer);
425
426
        // Now, alter the vertex declaration to change the position source
427
        // and the offsets of elements using the same buffer
428
        // Note that we don't change vertexCount, because the other buffer(s) are still the same
429
        // size after all
430
0
        updateVertexDeclaration(vertexDeclaration, posElem, VET_FLOAT3, newPosBufferSource);
431
0
    }
432
    //-----------------------------------------------------------------------
433
    void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, const BufferUsageList& bufferUsages,
434
                                       HardwareBufferManagerBase* mgr)
435
0
    {
436
0
        HardwareBufferManagerBase* pManager = mgr ? mgr : mMgr;
437
        // Firstly, close up any gaps in the buffer sources which might have arisen
438
0
        newDeclaration->closeGapsInSource();
439
440
        // Build up a list of both old and new elements in each buffer
441
0
        std::vector<uint8*> oldBufferLocks;
442
0
        std::vector<size_t> oldBufferVertexSizes;
443
0
        std::vector<uint8*> newBufferLocks;
444
0
        std::vector<size_t> newBufferVertexSizes;
445
0
        VertexBufferBinding* newBinding = pManager->createVertexBufferBinding();
446
0
        const auto& oldBindingMap = vertexBufferBinding->getBindings();
447
0
        VertexBufferBinding::VertexBufferBindingMap::const_iterator itBinding;
448
449
        // Pre-allocate old buffer locks
450
0
        if (!oldBindingMap.empty())
451
0
        {
452
0
            size_t count = oldBindingMap.rbegin()->first + 1;
453
0
            oldBufferLocks.resize(count);
454
0
            oldBufferVertexSizes.resize(count);
455
0
        }
456
457
0
        bool useShadowBuffer = false;
458
459
        // Lock all the old buffers for reading
460
0
        for (const auto& it : oldBindingMap)
461
0
        {
462
0
            assert(it.second->getNumVertices() >= vertexCount);
463
464
0
            oldBufferVertexSizes[it.first] = it.second->getVertexSize();
465
0
            oldBufferLocks[it.first] = (uint8*)it.second->lock(HardwareBuffer::HBL_READ_ONLY);
466
467
0
            useShadowBuffer |= it.second->hasShadowBuffer();
468
0
        }
469
        
470
        // Create new buffers and lock all for writing
471
0
        uint16 buf = 0;
472
0
        while (!newDeclaration->findElementsBySource(buf).empty())
473
0
        {
474
0
            size_t vertexSize = newDeclaration->getVertexSize(buf);
475
476
0
            auto vbuf = pManager->createVertexBuffer(vertexSize, vertexCount, bufferUsages[buf], useShadowBuffer);
477
0
            newBinding->setBinding(buf, vbuf);
478
479
0
            newBufferVertexSizes.push_back(vertexSize);
480
0
            newBufferLocks.push_back((uint8*)vbuf->lock(HardwareBuffer::HBL_DISCARD));
481
0
            buf++;
482
0
        }
483
484
        // Map from new to old elements
485
0
        std::map<const VertexElement*, const VertexElement*>  newToOldElementMap;
486
0
        const auto& newElemList = newDeclaration->getElements();
487
0
        for (const auto& newElem : newElemList)
488
0
        {
489
            // Find corresponding old element
490
0
            auto oldElem = vertexDeclaration->findElementBySemantic(newElem.getSemantic(), newElem.getIndex());
491
0
            if (!oldElem)
492
0
            {
493
                // Error, cannot create new elements with this method
494
0
                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Element not found in old vertex declaration");
495
0
            }
496
0
            newToOldElementMap[&newElem] = oldElem;
497
0
        }
498
        // Now iterate over the new buffers, pulling data out of the old ones
499
        // For each vertex
500
0
        for (size_t v = 0; v < vertexCount; ++v)
501
0
        {
502
            // For each (new) element
503
0
            for (const auto& newElem : newElemList)
504
0
            {
505
0
                const VertexElement* oldElem = newToOldElementMap[&newElem];
506
0
                auto oldBufferNo = oldElem->getSource();
507
0
                auto newBufferNo = newElem.getSource();
508
0
                auto pSrc = oldBufferLocks[oldBufferNo] + v * oldBufferVertexSizes[oldBufferNo];
509
0
                auto pDst = newBufferLocks[newBufferNo] + v * newBufferVertexSizes[newBufferNo];
510
0
                memcpy(pDst + newElem.getOffset(), pSrc + oldElem->getOffset(), newElem.getSize());
511
0
            }
512
0
        }
513
514
        // Unlock all buffers
515
0
        for (const auto& it : oldBindingMap)
516
0
        {
517
0
            it.second->unlock();
518
0
        }
519
0
        for (buf = 0; buf < newBinding->getBufferCount(); ++buf)
520
0
        {
521
0
            newBinding->getBuffer(buf)->unlock();
522
0
        }
523
524
        // Delete old binding & declaration
525
0
        if (mDeleteDclBinding)
526
0
        {
527
0
            pManager->destroyVertexBufferBinding(vertexBufferBinding);
528
0
            pManager->destroyVertexDeclaration(vertexDeclaration);
529
0
        }
530
531
        // Assign new binding and declaration
532
0
        vertexDeclaration = newDeclaration;
533
0
        vertexBufferBinding = newBinding;       
534
        // after this is complete, new manager should be used
535
0
        mMgr = pManager;
536
0
        mDeleteDclBinding = true; // because we created these through a manager
537
538
0
    }
539
    //-----------------------------------------------------------------------
540
    void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, HardwareBufferManagerBase* mgr)
541
0
    {
542
        // Derive the buffer usages from looking at where the source has come
543
        // from
544
0
        BufferUsageList usages;
545
0
        for (unsigned short b = 0; b <= newDeclaration->getMaxSource(); ++b)
546
0
        {
547
0
            VertexDeclaration::VertexElementList destElems = newDeclaration->findElementsBySource(b);
548
            // Initialise with most restrictive version
549
0
            uint8 final = HBU_GPU_ONLY;
550
0
            for (VertexElement& destelem : destElems)
551
0
            {
552
                // get source
553
0
                auto srcelem = vertexDeclaration->findElementBySemantic(destelem.getSemantic(), destelem.getIndex());
554
0
                OgreAssert(srcelem, "Semantic not found in existing declaration");
555
0
                const auto& srcbuf = vertexBufferBinding->getBuffer(srcelem->getSource());
556
                // improve flexibility only
557
0
                if (srcbuf->getUsage() & HBU_CPU_ONLY)
558
0
                {
559
                    // remove static
560
0
                    final &= ~HBU_GPU_TO_CPU;
561
                    // add dynamic
562
0
                    final |= HBU_CPU_ONLY;
563
0
                }
564
0
                if (!(srcbuf->getUsage() & HBU_DETAIL_WRITE_ONLY))
565
0
                {
566
                    // remove write only
567
0
                    final &= ~HBU_DETAIL_WRITE_ONLY;
568
0
                }
569
0
            }
570
0
            usages.push_back(static_cast<HardwareBufferUsage>(final));
571
0
        }
572
        // Call specific method
573
0
        reorganiseBuffers(newDeclaration, usages, mgr);
574
575
0
    }
576
    //-----------------------------------------------------------------------
577
    void VertexData::closeGapsInBindings(void)
578
0
    {
579
0
        if (!vertexBufferBinding->hasGaps())
580
0
            return;
581
582
        // Check for error first
583
0
        const VertexDeclaration::VertexElementList& allelems = 
584
0
            vertexDeclaration->getElements();
585
0
        for (auto& e : allelems)
586
0
        {
587
0
            if (!vertexBufferBinding->isBufferBound(e.getSource()))
588
0
            {
589
0
                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
590
0
                    "No buffer is bound to that element source.",
591
0
                    "VertexData::closeGapsInBindings");
592
0
            }
593
0
        }
594
595
        // Close gaps in the vertex buffer bindings
596
0
        VertexBufferBinding::BindingIndexMap bindingIndexMap;
597
0
        vertexBufferBinding->closeGaps(bindingIndexMap);
598
599
        // Modify vertex elements to reference to new buffer index
600
0
        unsigned short elemIndex = 0;
601
0
        for (auto ai = allelems.begin(); ai != allelems.end(); ++ai, ++elemIndex)
602
0
        {
603
0
            const VertexElement& elem = *ai;
604
0
            VertexBufferBinding::BindingIndexMap::const_iterator it =
605
0
                bindingIndexMap.find(elem.getSource());
606
0
            assert(it != bindingIndexMap.end());
607
0
            ushort targetSource = it->second;
608
0
            if (elem.getSource() != targetSource)
609
0
            {
610
0
                vertexDeclaration->modifyElement(elemIndex, 
611
0
                    targetSource, elem.getOffset(), elem.getType(), 
612
0
                    elem.getSemantic(), elem.getIndex());
613
0
            }
614
0
        }
615
0
    }
616
    //-----------------------------------------------------------------------
617
    void VertexData::removeUnusedBuffers(void)
618
0
    {
619
0
        std::set<ushort> usedBuffers;
620
621
        // Collect used buffers
622
0
        const VertexDeclaration::VertexElementList& allelems = 
623
0
            vertexDeclaration->getElements();
624
0
        for (auto& e : allelems)
625
0
        {
626
0
            usedBuffers.insert(e.getSource());
627
0
        }
628
629
        // Unset unused buffer bindings
630
0
        ushort count = vertexBufferBinding->getLastBoundIndex();
631
0
        for (ushort index = 0; index < count; ++index)
632
0
        {
633
0
            if (usedBuffers.find(index) == usedBuffers.end() &&
634
0
                vertexBufferBinding->isBufferBound(index))
635
0
            {
636
0
                vertexBufferBinding->unsetBinding(index);
637
0
            }
638
0
        }
639
640
        // Close gaps
641
0
        closeGapsInBindings();
642
0
    }
643
    //-----------------------------------------------------------------------
644
    void VertexData::convertPackedColour(VertexElementType, VertexElementType destType)
645
0
    {
646
0
        OgreAssert(destType == VET_UBYTE4_NORM, "Not supported");
647
648
0
        const VertexBufferBinding::VertexBufferBindingMap& bindMap = 
649
0
            vertexBufferBinding->getBindings();
650
0
        for (auto& m : bindMap)
651
0
        {
652
0
            const auto& elems =
653
0
                vertexDeclaration->findElementsBySource(m.first);
654
0
            bool conversionNeeded = false;
655
0
            for (auto& e : elems)
656
0
            {
657
0
                if (e.getType() == _DETAIL_SWAP_RB)
658
0
                {
659
0
                    conversionNeeded = true;
660
0
                }
661
0
            }
662
663
0
            if (conversionNeeded)
664
0
            {
665
0
                void* pBase = m.second->lock(HardwareBuffer::HBL_NORMAL);
666
667
0
                for (size_t v = 0; v < m.second->getNumVertices(); ++v)
668
0
                {
669
670
0
                    for (auto& e : elems)
671
0
                    {
672
0
                        if (e.getType() == _DETAIL_SWAP_RB)
673
0
                        {
674
0
                            uint32* pRGBA;
675
0
                            e.baseVertexPointerToElement(pBase, &pRGBA);
676
0
                            swapPackedRB(pRGBA);
677
0
                        }
678
0
                    }
679
0
                    pBase = static_cast<void*>(
680
0
                        static_cast<char*>(pBase) + m.second->getVertexSize());
681
0
                }
682
0
                m.second->unlock();
683
684
                // Modify the elements to reflect the changed type
685
0
                const VertexDeclaration::VertexElementList& allelems = 
686
0
                    vertexDeclaration->getElements();
687
0
                unsigned short elemIndex = 0;
688
0
                for (auto& e : allelems)
689
0
                {
690
0
                    if (e.getType() == _DETAIL_SWAP_RB)
691
0
                    {
692
0
                        vertexDeclaration->modifyElement(elemIndex,
693
0
                            e.getSource(), e.getOffset(), destType,
694
0
                            e.getSemantic(), e.getIndex());
695
0
                    }
696
0
                    ++elemIndex;
697
0
                }
698
0
            }
699
0
        } // each buffer
700
0
    }
701
    //-----------------------------------------------------------------------
702
    ushort VertexData::allocateHardwareAnimationElements(ushort count, bool animateNormals)
703
0
    {
704
        // Find first free texture coord set
705
0
        unsigned short texCoord = vertexDeclaration->getNextFreeTextureCoordinate();
706
0
        unsigned short freeCount = (ushort)(OGRE_MAX_TEXTURE_COORD_SETS - texCoord);
707
0
        if (animateNormals)
708
            // we need 2x the texture coords, round down
709
0
            freeCount /= 2;
710
        
711
0
        unsigned short supportedCount = std::min(freeCount, count);
712
        
713
        // Increase to correct size
714
0
        for (size_t c = hwAnimationDataList.size(); c < supportedCount; ++c)
715
0
        {
716
            // Create a new 3D texture coordinate set
717
0
            HardwareAnimationData data;
718
0
            data.targetBufferIndex = vertexBufferBinding->getNextIndex();
719
0
            vertexDeclaration->addElement(data.targetBufferIndex, 0, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoord++);
720
0
            if (animateNormals)
721
0
                    vertexDeclaration->addElement(data.targetBufferIndex, sizeof(float)*3, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoord++);
722
723
0
            hwAnimationDataList.push_back(data);
724
            // Vertex buffer will not be bound yet, we expect this to be done by the
725
            // caller when it becomes appropriate (e.g. through a VertexAnimationTrack)
726
0
        }
727
        
728
0
        return supportedCount;
729
0
    }
730
    VertexData* VertexData::_cloneRemovingBlendData() const
731
0
    {
732
        // Clone without copying data
733
0
        VertexData* ret = clone(false);
734
0
        bool removeIndices = Root::getSingleton().isBlendIndicesGpuRedundant();
735
0
        bool removeWeights = Root::getSingleton().isBlendWeightsGpuRedundant();
736
737
0
        unsigned short safeSource = 0xFFFF;
738
0
        auto blendIndexElem = vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
739
0
        if (blendIndexElem && removeIndices)
740
0
        {
741
            //save the source in order to prevent the next stage from unbinding it.
742
0
            safeSource = blendIndexElem->getSource();
743
            // Remove buffer reference
744
0
            ret->vertexBufferBinding->unsetBinding(blendIndexElem->getSource());
745
0
        }
746
747
        // Remove blend weights
748
0
        const VertexElement* blendWeightElem = vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
749
0
        if (removeWeights && blendWeightElem && blendWeightElem->getSource() != safeSource)
750
0
        {
751
            // Remove buffer reference
752
0
            ret->vertexBufferBinding->unsetBinding(blendWeightElem->getSource());
753
0
        }
754
755
        // remove elements from declaration
756
0
        if (removeIndices)
757
0
            ret->vertexDeclaration->removeElement(VES_BLEND_INDICES);
758
0
        if (removeWeights)
759
0
            ret->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
760
761
        // Close gaps in bindings for effective and safely
762
0
        if (removeWeights || removeIndices)
763
0
            ret->closeGapsInBindings();
764
765
0
        return ret;
766
0
    }
767
    //-----------------------------------------------------------------------
768
    //-----------------------------------------------------------------------
769
    IndexData::IndexData()
770
0
    {
771
0
        indexCount = 0;
772
0
        indexStart = 0;
773
        
774
0
    }
775
    //-----------------------------------------------------------------------
776
    IndexData::~IndexData()
777
0
    {
778
0
    }
779
    //-----------------------------------------------------------------------
780
    IndexData* IndexData::clone(bool copyData, HardwareBufferManagerBase* mgr) const
781
0
    {
782
0
        HardwareBufferManagerBase* pManager = mgr ? mgr : HardwareBufferManager::getSingletonPtr();
783
0
        IndexData* dest = OGRE_NEW IndexData();
784
0
        if (indexBuffer.get())
785
0
        {
786
0
            if (copyData)
787
0
            {
788
0
                dest->indexBuffer = pManager->createIndexBuffer(indexBuffer->getType(), indexBuffer->getNumIndexes(),
789
0
                    indexBuffer->getUsage(), indexBuffer->hasShadowBuffer());
790
0
                dest->indexBuffer->copyData(*indexBuffer, 0, 0, indexBuffer->getSizeInBytes(), true);
791
0
            }
792
0
            else
793
0
            {
794
0
                dest->indexBuffer = indexBuffer;
795
0
            }
796
0
        }
797
0
        dest->indexCount = indexCount;
798
0
        dest->indexStart = indexStart;
799
0
        return dest;
800
0
    }
801
    //-----------------------------------------------------------------------
802
    //-----------------------------------------------------------------------
803
    // Local Utility class for vertex cache optimizer
804
    class Triangle
805
    {
806
    public:
807
        enum EdgeMatchType {
808
            AB, BC, CA, ANY, NONE
809
        };
810
811
        uint32 a, b, c;     
812
813
        inline Triangle()
814
0
        {
815
0
        }
816
817
        inline Triangle( uint32 ta, uint32 tb, uint32 tc ) 
818
            : a( ta ), b( tb ), c( tc )
819
0
        {
820
0
        }
821
822
        inline Triangle( uint32 t[3] )
823
            : a( t[0] ), b( t[1] ), c( t[2] )
824
0
        {
825
0
        }
826
827
        inline Triangle( const Triangle& t )
828
0
            : a( t.a ), b( t.b ), c( t.c )
829
0
        {
830
0
        }
831
832
0
        inline Triangle& operator=(const Triangle& rhs) {
833
0
            a = rhs.a;
834
0
            b = rhs.b;
835
0
            c = rhs.c;
836
0
            return *this;
837
0
        }
838
839
        inline bool sharesEdge(const Triangle& t) const
840
0
        {
841
0
            return( (a == t.a && b == t.c) ||
842
0
                    (a == t.b && b == t.a) ||
843
0
                    (a == t.c && b == t.b) ||
844
0
                    (b == t.a && c == t.c) ||
845
0
                    (b == t.b && c == t.a) ||
846
0
                    (b == t.c && c == t.b) ||
847
0
                    (c == t.a && a == t.c) ||
848
0
                    (c == t.b && a == t.a) ||
849
0
                    (c == t.c && a == t.b) );
850
0
        }
851
852
        inline bool sharesEdge(const uint32 ea, const uint32 eb, const Triangle& t) const
853
0
        {
854
0
            return( (ea == t.a && eb == t.c) ||
855
0
                    (ea == t.b && eb == t.a) ||
856
0
                    (ea == t.c && eb == t.b) ); 
857
0
        }
858
859
        inline bool sharesEdge(const EdgeMatchType edge, const Triangle& t) const
860
0
        {
861
0
            if (edge == AB)
862
0
                return sharesEdge(a, b, t);
863
0
            else if (edge == BC)
864
0
                return sharesEdge(b, c, t);
865
0
            else if (edge == CA)
866
0
                return sharesEdge(c, a, t);
867
0
            else
868
0
                return (edge == ANY) == sharesEdge(t);
869
0
        }
870
871
        inline EdgeMatchType endoSharedEdge(const Triangle& t) const
872
0
        {
873
0
            if (sharesEdge(a, b, t)) return AB;
874
0
            if (sharesEdge(b, c, t)) return BC;
875
0
            if (sharesEdge(c, a, t)) return CA;
876
0
            return NONE;
877
0
        }
878
879
        inline EdgeMatchType exoSharedEdge(const Triangle& t) const
880
0
        {
881
0
            return t.endoSharedEdge(*this);
882
0
        }
883
884
        inline void shiftClockwise()
885
0
        {
886
0
            uint32 t = a;
887
0
            a = c;
888
0
            c = b;
889
0
            b = t;
890
0
        }
891
892
        inline void shiftCounterClockwise()
893
0
        {
894
0
            uint32 t = a;
895
0
            a = b;
896
0
            b = c;
897
0
            c = t;
898
0
        }
899
    };
900
    //-----------------------------------------------------------------------
901
    //-----------------------------------------------------------------------
902
    void IndexData::optimiseVertexCacheTriList(void)
903
0
    {
904
0
        if (indexBuffer->isLocked()) return;
905
906
0
        void *buffer = indexBuffer->lock(HardwareBuffer::HBL_NORMAL);
907
908
0
        Triangle* triangles;
909
910
0
        size_t nIndexes = indexCount;
911
0
        size_t nTriangles = nIndexes / 3;
912
0
        size_t i, j;
913
0
        uint16 *source = 0;
914
915
0
        if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT)
916
0
        {
917
0
            triangles = OGRE_ALLOC_T(Triangle, nTriangles, MEMCATEGORY_GEOMETRY);
918
0
            source = (uint16 *)buffer;
919
0
            uint32 *dest = (uint32 *)triangles;
920
0
            for (i = 0; i < nIndexes; ++i) dest[i] = source[i];
921
0
        }
922
0
        else
923
0
            triangles = static_cast<Triangle*>(buffer);
924
925
        // sort triangles based on shared edges
926
0
        uint32 *destlist = OGRE_ALLOC_T(uint32, nTriangles, MEMCATEGORY_GEOMETRY);
927
0
        unsigned char *visited = OGRE_ALLOC_T(unsigned char, nTriangles, MEMCATEGORY_GEOMETRY);
928
929
0
        for (i = 0; i < nTriangles; ++i) visited[i] = 0;
930
931
0
        uint32 start = 0, ti = 0, destcount = 0;
932
933
0
        bool found = false;
934
0
        for (i = 0; i < nTriangles; ++i)
935
0
        {
936
0
            if (found)
937
0
                found = false;
938
0
            else
939
0
            {
940
0
                while (visited[start++]);
941
0
                ti = start - 1;
942
0
            }
943
944
0
            destlist[destcount++] = ti;
945
0
            visited[ti] = 1;
946
947
0
            for (j = start; j < nTriangles; ++j)
948
0
            {
949
0
                if (visited[j]) continue;
950
                
951
0
                if (triangles[ti].sharesEdge(triangles[j]))
952
0
                {
953
0
                    found = true;
954
0
                    ti = static_cast<uint32>(j);
955
0
                    break;
956
0
                }
957
0
            }
958
0
        }
959
960
0
        if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT)
961
0
        {
962
            // reorder the indexbuffer
963
0
            j = 0;
964
0
            for (i = 0; i < nTriangles; ++i)
965
0
            {
966
0
                Triangle *t = &triangles[destlist[i]];
967
0
                if(source)
968
0
                {
969
0
                    source[j++] = (uint16)t->a;
970
0
                    source[j++] = (uint16)t->b;
971
0
                    source[j++] = (uint16)t->c;
972
0
                }
973
0
            }
974
0
            OGRE_FREE(triangles, MEMCATEGORY_GEOMETRY);
975
0
        }
976
0
        else
977
0
        {
978
0
            uint32 *reflist = OGRE_ALLOC_T(uint32, nTriangles, MEMCATEGORY_GEOMETRY);
979
980
            // fill the referencebuffer
981
0
            for (i = 0; i < nTriangles; ++i)
982
0
                reflist[destlist[i]] = static_cast<uint32>(i);
983
            
984
            // reorder the indexbuffer
985
0
            for (i = 0; i < nTriangles; ++i)
986
0
            {
987
0
                j = destlist[i];
988
0
                if (i == j) continue; // do not move triangle
989
990
                // swap triangles
991
992
0
                Triangle t = triangles[i];
993
0
                triangles[i] = triangles[j];
994
0
                triangles[j] = t;
995
996
                // change reference
997
0
                destlist[reflist[i]] = static_cast<uint32>(j);
998
                // destlist[i] = i; // not needed, it will not be used
999
0
            }
1000
1001
0
            OGRE_FREE(reflist, MEMCATEGORY_GEOMETRY);
1002
0
        }
1003
1004
0
        OGRE_FREE(destlist, MEMCATEGORY_GEOMETRY);
1005
0
        OGRE_FREE(visited, MEMCATEGORY_GEOMETRY);
1006
                    
1007
0
        indexBuffer->unlock();
1008
0
    }
1009
    //-----------------------------------------------------------------------
1010
    //-----------------------------------------------------------------------
1011
    void VertexCacheProfiler::profile(const HardwareIndexBufferSharedPtr& indexBuffer)
1012
0
    {
1013
0
        if (indexBuffer->isLocked()) return;
1014
1015
0
        uint16 *shortbuffer = (uint16 *)indexBuffer->lock(HardwareBuffer::HBL_READ_ONLY);
1016
1017
0
        if (indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT)
1018
0
            for (unsigned int i = 0; i < indexBuffer->getNumIndexes(); ++i)
1019
0
                inCache(shortbuffer[i]);
1020
0
        else
1021
0
        {
1022
0
            uint32 *buffer = (uint32 *)shortbuffer;
1023
0
            for (unsigned int i = 0; i < indexBuffer->getNumIndexes(); ++i)
1024
0
                inCache(buffer[i]);
1025
0
        }
1026
1027
0
        indexBuffer->unlock();
1028
1029
0
        triangles += indexBuffer->getNumIndexes()/3;
1030
0
    }
1031
1032
    //-----------------------------------------------------------------------
1033
    bool VertexCacheProfiler::inCache(unsigned int index)
1034
0
    {
1035
0
        for (unsigned int i = 0; i < buffersize; ++i)
1036
0
        {
1037
0
            if (index == cache[i])
1038
0
            {
1039
0
                hit++;
1040
0
                return true;
1041
0
            }
1042
0
        }
1043
1044
0
        miss++;
1045
0
        cache[tail++] = index;
1046
0
        tail %= size;
1047
1048
0
        if (buffersize < size) buffersize++;
1049
1050
0
        return false;
1051
0
    }
1052
    
1053
1054
}