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

Revision 692, 87.0 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

RevLine 
[692]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
27#include "OgreMeshSerializerImpl.h"
28#include "OgreMeshFileFormat.h"
29#include "OgreMesh.h"
30#include "OgreSubMesh.h"
31#include "OgreException.h"
32#include "OgreLogManager.h"
33#include "OgreSkeleton.h"
34#include "OgreHardwareBufferManager.h"
35#include "OgreMaterial.h"
36#include "OgreTechnique.h"
37#include "OgrePass.h"
38#include "OgreAnimation.h"
39#include "OgreAnimationTrack.h"
40#include "OgreKeyFrame.h"
41#include "OgreRoot.h"
42
43#if OGRE_COMPILER == OGRE_COMPILER_MSVC
44// Disable conversion warnings, we do a lot of them, intentionally
45#   pragma warning (disable : 4267)
46#endif
47
48
49namespace Ogre {
50
51    /// stream overhead = ID + size
52    const long STREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32);
53    //---------------------------------------------------------------------
54    MeshSerializerImpl::MeshSerializerImpl()
55    {
56
57        // Version number
58        mVersion = "[MeshSerializer_v1.30]";
59    }
60    //---------------------------------------------------------------------
61    MeshSerializerImpl::~MeshSerializerImpl()
62    {
63    }
64    //---------------------------------------------------------------------
65    void MeshSerializerImpl::exportMesh(const Mesh* pMesh,
66                const String& filename, Endian endianMode)
67    {
68        LogManager::getSingleton().logMessage("MeshSerializer writing mesh data to " + filename + "...");
69
70                // Decide on endian mode
71                determineEndianness(endianMode);
72
73        // Check that the mesh has it's bounds set
74        if (pMesh->getBounds().isNull() || pMesh->getBoundingSphereRadius() == 0.0f)
75        {
76            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The Mesh you have supplied does not have its"
77                " bounds completely defined. Define them first before exporting.",
78                "MeshSerializerImpl::exportMesh");
79        }
80        mpfFile = fopen(filename.c_str(), "wb");
81                if (!mpfFile)
82                {
83                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
84                                "Unable to open file " + filename + " for writing",
85                                "MeshSerializerImpl::exportMesh");
86                }
87
88        writeFileHeader();
89        LogManager::getSingleton().logMessage("File header written.");
90
91
92        LogManager::getSingleton().logMessage("Writing mesh data...");
93        writeMesh(pMesh);
94        LogManager::getSingleton().logMessage("Mesh data exported.");
95
96        fclose(mpfFile);
97        LogManager::getSingleton().logMessage("MeshSerializer export successful.");
98    }
99    //---------------------------------------------------------------------
100    void MeshSerializerImpl::importMesh(DataStreamPtr& stream, Mesh* pMesh)
101    {
102                // Determine endianness (must be the first thing we do!)
103                determineEndianness(stream);
104
105        // Check header
106        readFileHeader(stream);
107
108        unsigned short streamID;
109        while(!stream->eof())
110        {
111            streamID = readChunk(stream);
112            switch (streamID)
113            {
114            case M_MESH:
115                readMesh(stream, pMesh);
116                break;
117                        }
118
119        }
120    }
121    //---------------------------------------------------------------------
122    void MeshSerializerImpl::writeMesh(const Mesh* pMesh)
123    {
124        // Header
125        writeChunkHeader(M_MESH, calcMeshSize(pMesh));
126
127                // bool skeletallyAnimated
128                bool skelAnim = pMesh->hasSkeleton();
129                writeBools(&skelAnim, 1);
130
131        // Write shared geometry
132        if (pMesh->sharedVertexData)
133            writeGeometry(pMesh->sharedVertexData);
134
135        // Write Submeshes
136        for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
137        {
138            LogManager::getSingleton().logMessage("Writing submesh...");
139            writeSubMesh(pMesh->getSubMesh(i));
140            LogManager::getSingleton().logMessage("Submesh exported.");
141        }
142
143        // Write skeleton info if required
144        if (pMesh->hasSkeleton())
145        {
146            LogManager::getSingleton().logMessage("Exporting skeleton link...");
147            // Write skeleton link
148            writeSkeletonLink(pMesh->getSkeletonName());
149            LogManager::getSingleton().logMessage("Skeleton link exported.");
150
151            // Write bone assignments
152            if (!pMesh->mBoneAssignments.empty())
153            {
154                LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");
155
156                Mesh::VertexBoneAssignmentList::const_iterator vi;
157                for (vi = pMesh->mBoneAssignments.begin();
158                vi != pMesh->mBoneAssignments.end(); ++vi)
159                {
160                    writeMeshBoneAssignment(vi->second);
161                }
162
163                LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
164            }
165        }
166
167        // Write LOD data if any
168        if (pMesh->getNumLodLevels() > 1)
169        {
170            LogManager::getSingleton().logMessage("Exporting LOD information....");
171            writeLodInfo(pMesh);
172            LogManager::getSingleton().logMessage("LOD information exported.");
173
174        }
175        // Write bounds information
176        LogManager::getSingleton().logMessage("Exporting bounds information....");
177        writeBoundsInfo(pMesh);
178        LogManager::getSingleton().logMessage("Bounds information exported.");
179
180                // Write submesh name table
181                LogManager::getSingleton().logMessage("Exporting submesh name table...");
182                writeSubMeshNameTable(pMesh);
183                LogManager::getSingleton().logMessage("Submesh name table exported.");
184
185                // Write edge lists
186                if (pMesh->isEdgeListBuilt())
187                {
188                        LogManager::getSingleton().logMessage("Exporting edge lists...");
189                        writeEdgeList(pMesh);
190                        LogManager::getSingleton().logMessage("Edge lists exported");
191                }
192
193                // Write morph animation
194                writePoses(pMesh);
195                if (pMesh->hasVertexAnimation())
196                {
197                        writeAnimations(pMesh);
198                }
199    }
200    //---------------------------------------------------------------------
201        // Added by DrEvil
202        void MeshSerializerImpl::writeSubMeshNameTable(const Mesh* pMesh)
203        {
204                // Header
205                writeChunkHeader(M_SUBMESH_NAME_TABLE, calcSubMeshNameTableSize(pMesh));
206
207                // Loop through and save out the index and names.
208                Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();
209
210                while(it != pMesh->mSubMeshNameMap.end())
211                {
212                        // Header
213                        writeChunkHeader(M_SUBMESH_NAME_TABLE_ELEMENT, STREAM_OVERHEAD_SIZE +
214                                sizeof(unsigned short) + (unsigned long)it->first.length() + 1);
215
216                        // write the index
217                        writeShorts(&it->second, 1);
218                        // name
219                writeString(it->first);
220
221                        ++it;
222                }
223        }
224    //---------------------------------------------------------------------
225    void MeshSerializerImpl::writeSubMesh(const SubMesh* s)
226    {
227        // Header
228        writeChunkHeader(M_SUBMESH, calcSubMeshSize(s));
229
230        // char* materialName
231        writeString(s->getMaterialName());
232
233        // bool useSharedVertices
234        writeBools(&s->useSharedVertices, 1);
235
236                unsigned int indexCount = s->indexData->indexCount;
237        writeInts(&indexCount, 1);
238
239        // bool indexes32Bit
240        bool idx32bit = (s->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
241        writeBools(&idx32bit, 1);
242
243        // unsigned short* faceVertexIndices ((indexCount)
244        HardwareIndexBufferSharedPtr ibuf = s->indexData->indexBuffer;
245        void* pIdx = ibuf->lock(HardwareBuffer::HBL_READ_ONLY);
246        if (idx32bit)
247        {
248            unsigned int* pIdx32 = static_cast<unsigned int*>(pIdx);
249            writeInts(pIdx32, s->indexData->indexCount);
250        }
251        else
252        {
253            unsigned short* pIdx16 = static_cast<unsigned short*>(pIdx);
254            writeShorts(pIdx16, s->indexData->indexCount);
255        }
256        ibuf->unlock();
257
258        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
259        if (!s->useSharedVertices)
260        {
261            writeGeometry(s->vertexData);
262        }
263
264        // end of sub mesh chunk
265
266        // write out texture alias chunks
267        writeSubMeshTextureAliases(s);
268
269        // Operation type
270        writeSubMeshOperation(s);
271
272        // Bone assignments
273        if (!s->mBoneAssignments.empty())
274        {
275            LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");
276
277            SubMesh::VertexBoneAssignmentList::const_iterator vi;
278            for (vi = s->mBoneAssignments.begin();
279            vi != s->mBoneAssignments.end(); ++vi)
280            {
281                writeSubMeshBoneAssignment(vi->second);
282            }
283
284            LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
285        }
286
287
288    }
289
290    //---------------------------------------------------------------------
291    void MeshSerializerImpl::writeSubMeshTextureAliases(const SubMesh* s)
292    {
293        size_t chunkSize;
294        AliasTextureNamePairList::const_iterator i;
295
296                LogManager::getSingleton().logMessage("Exporting submesh texture aliases...");
297
298        // iterate through texture aliases and write them out as a chunk
299        for (i = s->mTextureAliases.begin(); i != s->mTextureAliases.end(); ++i)
300        {
301            // calculate chunk size based on string length + 1.  Add 1 for the line feed.
302            chunkSize = STREAM_OVERHEAD_SIZE + i->first.length() + i->second.length() + 2;
303                        writeChunkHeader(M_SUBMESH_TEXTURE_ALIAS, chunkSize);
304            // write out alias name
305            writeString(i->first);
306            // write out texture name
307            writeString(i->second);
308        }
309
310                LogManager::getSingleton().logMessage("Submesh texture aliases exported.");
311    }
312
313    //---------------------------------------------------------------------
314    void MeshSerializerImpl::writeSubMeshOperation(const SubMesh* sm)
315    {
316        // Header
317        writeChunkHeader(M_SUBMESH_OPERATION, calcSubMeshOperationSize(sm));
318
319        // unsigned short operationType
320        unsigned short opType = static_cast<unsigned short>(sm->operationType);
321        writeShorts(&opType, 1);
322    }
323    //---------------------------------------------------------------------
324    void MeshSerializerImpl::writeGeometry(const VertexData* vertexData)
325    {
326                // calc size
327        const VertexDeclaration::VertexElementList& elemList =
328            vertexData->vertexDeclaration->getElements();
329        const VertexBufferBinding::VertexBufferBindingMap& bindings =
330            vertexData->vertexBufferBinding->getBindings();
331        VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbiend;
332
333                size_t size = STREAM_OVERHEAD_SIZE + sizeof(unsigned int) + // base
334                        (STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5)); // elements
335        vbiend = bindings.end();
336                for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
337                {
338                        const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
339                        size += (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
340                }
341
342                // Header
343        writeChunkHeader(M_GEOMETRY, size);
344
345        unsigned int vertexCount = vertexData->vertexCount;
346        writeInts(&vertexCount, 1);
347
348                // Vertex declaration
349                size = STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5);
350                writeChunkHeader(M_GEOMETRY_VERTEX_DECLARATION, size);
351
352        VertexDeclaration::VertexElementList::const_iterator vei, veiend;
353                veiend = elemList.end();
354                unsigned short tmp;
355                size = STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5;
356                for (vei = elemList.begin(); vei != veiend; ++vei)
357                {
358                        const VertexElement& elem = *vei;
359                        writeChunkHeader(M_GEOMETRY_VERTEX_ELEMENT, size);
360                        // unsigned short source;       // buffer bind source
361                        tmp = elem.getSource();
362                        writeShorts(&tmp, 1);
363                        // unsigned short type;         // VertexElementType
364                        tmp = static_cast<unsigned short>(elem.getType());
365                        writeShorts(&tmp, 1);
366                        // unsigned short semantic; // VertexElementSemantic
367                        tmp = static_cast<unsigned short>(elem.getSemantic());
368                        writeShorts(&tmp, 1);
369                        // unsigned short offset;       // start offset in buffer in bytes
370                        tmp = static_cast<unsigned short>(elem.getOffset());
371                        writeShorts(&tmp, 1);
372                        // unsigned short index;        // index of the semantic (for colours and texture coords)
373                        tmp = elem.getIndex();
374                        writeShorts(&tmp, 1);
375
376                }
377
378                // Buffers and bindings
379                vbiend = bindings.end();
380                for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
381                {
382                        const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
383                        size = (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
384                        writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER,  size);
385                        // unsigned short bindIndex;    // Index to bind this buffer to
386                        tmp = vbi->first;
387                        writeShorts(&tmp, 1);
388                        // unsigned short vertexSize;   // Per-vertex size, must agree with declaration at this index
389                        tmp = (unsigned short)vbuf->getVertexSize();
390                        writeShorts(&tmp, 1);
391
392                        // Data
393                        size = STREAM_OVERHEAD_SIZE + vbuf->getSizeInBytes();
394                        writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size);
395                        void* pBuf = vbuf->lock(HardwareBuffer::HBL_READ_ONLY);
396
397                        if (mFlipEndian)
398                        {
399                                // endian conversion
400                                // Copy data
401                                unsigned char* tempData = new unsigned char[vbuf->getSizeInBytes()];
402                                memcpy(tempData, pBuf, vbuf->getSizeInBytes());
403                                flipToLittleEndian(
404                                        tempData,
405                                        vertexData->vertexCount,
406                                        vbuf->getVertexSize(),
407                                        vertexData->vertexDeclaration->findElementsBySource(vbi->first));
408                                writeData(tempData, vbuf->getVertexSize(), vertexData->vertexCount);
409                                delete [] tempData;
410                        }
411                        else
412                        {
413                                writeData(pBuf, vbuf->getVertexSize(), vertexData->vertexCount);
414                        }
415            vbuf->unlock();
416                }
417
418
419    }
420    //---------------------------------------------------------------------
421        size_t MeshSerializerImpl::calcSubMeshNameTableSize(const Mesh* pMesh)
422        {
423                size_t size = STREAM_OVERHEAD_SIZE;
424                // Figure out the size of the Name table.
425                // Iterate through the subMeshList & add up the size of the indexes and names.
426                Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();
427                while(it != pMesh->mSubMeshNameMap.end())
428                {
429                        // size of the index + header size for each element chunk
430                        size += STREAM_OVERHEAD_SIZE + sizeof(uint16);
431                        // name
432                        size += it->first.length() + 1;
433
434                        ++it;
435                }
436
437                // size of the sub-mesh name table.
438                return size;
439        }
440    //---------------------------------------------------------------------
441    size_t MeshSerializerImpl::calcMeshSize(const Mesh* pMesh)
442    {
443        size_t size = STREAM_OVERHEAD_SIZE;
444
445        // Num shared vertices
446        size += sizeof(uint32);
447
448        // Geometry
449        if (pMesh->sharedVertexData && pMesh->sharedVertexData->vertexCount > 0)
450        {
451            size += calcGeometrySize(pMesh->sharedVertexData);
452        }
453
454        // Submeshes
455        for (unsigned short i = 0; i < pMesh->getNumSubMeshes(); ++i)
456        {
457            size += calcSubMeshSize(pMesh->getSubMesh(i));
458        }
459
460        // Skeleton link
461        if (pMesh->hasSkeleton())
462        {
463            size += calcSkeletonLinkSize(pMesh->getSkeletonName());
464        }
465
466                // Submesh name table
467                size += calcSubMeshNameTableSize(pMesh);
468
469                // Edge list
470                if (pMesh->isEdgeListBuilt())
471                {
472                        size += calcEdgeListSize(pMesh);
473                }
474
475                // Animations
476                for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
477                {
478                        Animation* anim = pMesh->getAnimation(a);
479                        size += calcAnimationSize(anim);
480                }
481
482                return size;
483    }
484    //---------------------------------------------------------------------
485    size_t MeshSerializerImpl::calcSubMeshSize(const SubMesh* pSub)
486    {
487        size_t size = STREAM_OVERHEAD_SIZE;
488
489        // Material name
490        size += pSub->getMaterialName().length() + 1;
491
492        // bool useSharedVertices
493        size += sizeof(bool);
494        // unsigned int indexCount
495        size += sizeof(unsigned int);
496        // bool indexes32bit
497        size += sizeof(bool);
498        // unsigned int* faceVertexIndices
499        size += sizeof(unsigned int) * pSub->indexData->indexCount;
500
501        // Geometry
502        if (!pSub->useSharedVertices)
503        {
504            size += calcGeometrySize(pSub->vertexData);
505        }
506
507        size += calcSubMeshTextureAliasesSize(pSub);
508        size += calcSubMeshOperationSize(pSub);
509
510        // Bone assignments
511        if (!pSub->mBoneAssignments.empty())
512        {
513            SubMesh::VertexBoneAssignmentList::const_iterator vi;
514            for (vi = pSub->mBoneAssignments.begin();
515                 vi != pSub->mBoneAssignments.end(); ++vi)
516            {
517                size += calcBoneAssignmentSize();
518            }
519        }
520
521        return size;
522    }
523    //---------------------------------------------------------------------
524    size_t MeshSerializerImpl::calcSubMeshOperationSize(const SubMesh* pSub)
525    {
526        return STREAM_OVERHEAD_SIZE + sizeof(uint16);
527    }
528    //---------------------------------------------------------------------
529    size_t MeshSerializerImpl::calcSubMeshTextureAliasesSize(const SubMesh* pSub)
530    {
531        size_t chunkSize = 0;
532        AliasTextureNamePairList::const_iterator i;
533
534        // iterate through texture alias map and calc size of strings
535        for (i = pSub->mTextureAliases.begin(); i != pSub->mTextureAliases.end(); ++i)
536        {
537            // calculate chunk size based on string length + 1.  Add 1 for the line feed.
538            chunkSize += STREAM_OVERHEAD_SIZE + i->first.length() + i->second.length() + 2;
539        }
540
541        return chunkSize;
542    }
543    //---------------------------------------------------------------------
544    size_t MeshSerializerImpl::calcGeometrySize(const VertexData* vertexData)
545    {
546        size_t size = STREAM_OVERHEAD_SIZE;
547
548        // Num vertices
549        size += sizeof(unsigned int);
550
551        const VertexDeclaration::VertexElementList& elems =
552            vertexData->vertexDeclaration->getElements();
553
554        VertexDeclaration::VertexElementList::const_iterator i, iend;
555        iend = elems.end();
556        for (i = elems.begin(); i != iend; ++i)
557        {
558            const VertexElement& elem = *i;
559            // Vertex element
560            size += VertexElement::getTypeSize(elem.getType()) * vertexData->vertexCount;
561        }
562        return size;
563    }
564    //---------------------------------------------------------------------
565    void MeshSerializerImpl::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
566        VertexData* dest)
567    {
568
569        dest->vertexStart = 0;
570
571        unsigned int vertexCount = 0;
572        readInts(stream, &vertexCount, 1);
573        dest->vertexCount = vertexCount;
574
575        // Find optional geometry streams
576        if (!stream->eof())
577        {
578            unsigned short streamID = readChunk(stream);
579            while(!stream->eof() &&
580                (streamID == M_GEOMETRY_VERTEX_DECLARATION ||
581                 streamID == M_GEOMETRY_VERTEX_BUFFER ))
582            {
583                switch (streamID)
584                {
585                case M_GEOMETRY_VERTEX_DECLARATION:
586                    readGeometryVertexDeclaration(stream, pMesh, dest);
587                    break;
588                case M_GEOMETRY_VERTEX_BUFFER:
589                    readGeometryVertexBuffer(stream, pMesh, dest);
590                    break;
591                }
592                // Get next stream
593                if (!stream->eof())
594                {
595                    streamID = readChunk(stream);
596                }
597            }
598            if (!stream->eof())
599            {
600                // Backpedal back to start of non-submesh stream
601                stream->skip(-STREAM_OVERHEAD_SIZE);
602            }
603        }
604
605                // Perform any necessary colour conversion for an active rendersystem
606                if (Root::getSingletonPtr() && Root::getSingleton().getRenderSystem())
607                {
608                        // We don't know the source type if it's VET_COLOUR, but assume ARGB
609                        // since that's the most common. Won't get used unless the mesh is
610                        // ambiguous anyway, which will have been warned about in the log
611                        dest->convertPackedColour(VET_COLOUR_ARGB,
612                                VertexElement::getBestColourVertexElementType());
613                }
614    }
615    //---------------------------------------------------------------------
616    void MeshSerializerImpl::readGeometryVertexDeclaration(DataStreamPtr& stream,
617        Mesh* pMesh, VertexData* dest)
618    {
619        // Find optional geometry streams
620        if (!stream->eof())
621        {
622            unsigned short streamID = readChunk(stream);
623            while(!stream->eof() &&
624                (streamID == M_GEOMETRY_VERTEX_ELEMENT ))
625            {
626                switch (streamID)
627                {
628                case M_GEOMETRY_VERTEX_ELEMENT:
629                    readGeometryVertexElement(stream, pMesh, dest);
630                    break;
631                }
632                // Get next stream
633                if (!stream->eof())
634                {
635                    streamID = readChunk(stream);
636                }
637            }
638            if (!stream->eof())
639            {
640                // Backpedal back to start of non-submesh stream
641                stream->skip(-STREAM_OVERHEAD_SIZE);
642            }
643        }
644
645        }
646    //---------------------------------------------------------------------
647    void MeshSerializerImpl::readGeometryVertexElement(DataStreamPtr& stream,
648        Mesh* pMesh, VertexData* dest)
649    {
650                unsigned short source, offset, index, tmp;
651                VertexElementType vType;
652                VertexElementSemantic vSemantic;
653                // unsigned short source;       // buffer bind source
654                readShorts(stream, &source, 1);
655                // unsigned short type;         // VertexElementType
656                readShorts(stream, &tmp, 1);
657                vType = static_cast<VertexElementType>(tmp);
658                // unsigned short semantic; // VertexElementSemantic
659                readShorts(stream, &tmp, 1);
660                vSemantic = static_cast<VertexElementSemantic>(tmp);
661                // unsigned short offset;       // start offset in buffer in bytes
662                readShorts(stream, &offset, 1);
663                // unsigned short index;        // index of the semantic
664                readShorts(stream, &index, 1);
665
666                dest->vertexDeclaration->addElement(source, offset, vType, vSemantic, index);
667
668                if (vType == VET_COLOUR)
669                {
670                        StringUtil::StrStreamType s;
671                        s << "Warning: VET_COLOUR element type is deprecated, you should use "
672                                << "one of the more specific types to indicate the byte order. "
673                                << "Use OgreMeshUpgrade on " << pMesh->getName() << " as soon as possible. ";
674                        LogManager::getSingleton().logMessage(s.str());
675                }
676
677        }
678    //---------------------------------------------------------------------
679    void MeshSerializerImpl::readGeometryVertexBuffer(DataStreamPtr& stream,
680        Mesh* pMesh, VertexData* dest)
681    {
682                unsigned short bindIndex, vertexSize;
683                // unsigned short bindIndex;    // Index to bind this buffer to
684                readShorts(stream, &bindIndex, 1);
685                // unsigned short vertexSize;   // Per-vertex size, must agree with declaration at this index
686                readShorts(stream, &vertexSize, 1);
687
688                // Check for vertex data header
689                unsigned short headerID;
690                headerID = readChunk(stream);
691                if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA)
692                {
693                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Can't find vertex buffer data area",
694                "MeshSerializerImpl::readGeometryVertexBuffer");
695                }
696                // Check that vertex size agrees
697                if (dest->vertexDeclaration->getVertexSize(bindIndex) != vertexSize)
698                {
699                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer vertex size does not agree with vertex declaration",
700                "MeshSerializerImpl::readGeometryVertexBuffer");
701                }
702
703                // Create / populate vertex buffer
704                HardwareVertexBufferSharedPtr vbuf;
705        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
706            vertexSize,
707            dest->vertexCount,
708            pMesh->mVertexBufferUsage,
709                        pMesh->mVertexBufferShadowBuffer);
710        void* pBuf = vbuf->lock(HardwareBuffer::HBL_DISCARD);
711        stream->read(pBuf, dest->vertexCount * vertexSize);
712
713                // endian conversion for OSX
714                flipFromLittleEndian(
715                        pBuf,
716                        dest->vertexCount,
717                        vertexSize,
718                        dest->vertexDeclaration->findElementsBySource(bindIndex));
719        vbuf->unlock();
720
721                // Set binding
722        dest->vertexBufferBinding->setBinding(bindIndex, vbuf);
723
724        }
725    //---------------------------------------------------------------------
726        void MeshSerializerImpl::readSubMeshNameTable(DataStreamPtr& stream, Mesh* pMesh)
727        {
728                // The map for
729                std::map<unsigned short, String> subMeshNames;
730                unsigned short streamID, subMeshIndex;
731
732                // Need something to store the index, and the objects name
733                // This table is a method that imported meshes can retain their naming
734                // so that the names established in the modelling software can be used
735                // to get the sub-meshes by name. The exporter must support exporting
736                // the optional stream M_SUBMESH_NAME_TABLE.
737
738        // Read in all the sub-streams. Each sub-stream should contain an index and Ogre::String for the name.
739                if (!stream->eof())
740                {
741                        streamID = readChunk(stream);
742                        while(!stream->eof() && (streamID == M_SUBMESH_NAME_TABLE_ELEMENT ))
743                        {
744                                // Read in the index of the submesh.
745                                readShorts(stream, &subMeshIndex, 1);
746                                // Read in the String and map it to its index.
747                                subMeshNames[subMeshIndex] = readString(stream);
748
749                                // If we're not end of file get the next stream ID
750                                if (!stream->eof())
751                                        streamID = readChunk(stream);
752                        }
753                        if (!stream->eof())
754                        {
755                                // Backpedal back to start of stream
756                                stream->skip(-STREAM_OVERHEAD_SIZE);
757                        }
758                }
759
760                // Set all the submeshes names
761                // ?
762
763                // Loop through and save out the index and names.
764                std::map<unsigned short, String>::const_iterator it = subMeshNames.begin();
765
766                while(it != subMeshNames.end())
767                {
768                        // Name this submesh to the stored name.
769                        pMesh->nameSubMesh(it->second, it->first);
770                        ++it;
771                }
772
773
774
775        }
776    //---------------------------------------------------------------------
777    void MeshSerializerImpl::readMesh(DataStreamPtr& stream, Mesh* pMesh)
778    {
779        unsigned short streamID;
780
781        // Never automatically build edge lists for this version
782        // expect them in the file or not at all
783        pMesh->mAutoBuildEdgeLists = false;
784
785                // bool skeletallyAnimated
786                readBools(stream, &mIsSkeletallyAnimated, 1);
787
788        // Find all substreams
789        if (!stream->eof())
790        {
791            streamID = readChunk(stream);
792            while(!stream->eof() &&
793                (streamID == M_GEOMETRY ||
794                                 streamID == M_SUBMESH ||
795                 streamID == M_MESH_SKELETON_LINK ||
796                 streamID == M_MESH_BONE_ASSIGNMENT ||
797                                 streamID == M_MESH_LOD ||
798                 streamID == M_MESH_BOUNDS ||
799                                 streamID == M_SUBMESH_NAME_TABLE ||
800                                 streamID == M_EDGE_LISTS ||
801                                 streamID == M_POSES ||
802                                 streamID == M_ANIMATIONS))
803            {
804                switch(streamID)
805                {
806                                case M_GEOMETRY:
807                                        pMesh->sharedVertexData = new VertexData();
808                                        try {
809                                                readGeometry(stream, pMesh, pMesh->sharedVertexData);
810                                        }
811                                        catch (Exception& e)
812                                        {
813                                                if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
814                                                {
815                                                        // duff geometry data entry with 0 vertices
816                                                        delete pMesh->sharedVertexData;
817                                                        pMesh->sharedVertexData = 0;
818                                                        // Skip this stream (pointer will have been returned to just after header)
819                                                        stream->skip(mCurrentstreamLen - STREAM_OVERHEAD_SIZE);
820                                                }
821                                                else
822                                                {
823                                                        throw;
824                                                }
825                                        }
826                                        break;
827                case M_SUBMESH:
828                    readSubMesh(stream, pMesh);
829                    break;
830                case M_MESH_SKELETON_LINK:
831                    readSkeletonLink(stream, pMesh);
832                    break;
833                case M_MESH_BONE_ASSIGNMENT:
834                    readMeshBoneAssignment(stream, pMesh);
835                    break;
836                case M_MESH_LOD:
837                                        readMeshLodInfo(stream, pMesh);
838                                        break;
839                case M_MESH_BOUNDS:
840                    readBoundsInfo(stream, pMesh);
841                    break;
842                                case M_SUBMESH_NAME_TABLE:
843                    readSubMeshNameTable(stream, pMesh);
844                                        break;
845                case M_EDGE_LISTS:
846                    readEdgeList(stream, pMesh);
847                    break;
848                                case M_POSES:
849                                        readPoses(stream, pMesh);
850                                        break;
851                                case M_ANIMATIONS:
852                                        readAnimations(stream, pMesh);
853                                        break;
854
855                }
856
857                if (!stream->eof())
858                {
859                    streamID = readChunk(stream);
860                }
861
862            }
863            if (!stream->eof())
864            {
865                // Backpedal back to start of stream
866                stream->skip(-STREAM_OVERHEAD_SIZE);
867            }
868        }
869
870    }
871    //---------------------------------------------------------------------
872    void MeshSerializerImpl::readSubMesh(DataStreamPtr& stream, Mesh* pMesh)
873    {
874        unsigned short streamID;
875
876        SubMesh* sm = pMesh->createSubMesh();
877        // char* materialName
878        String materialName = readString(stream);
879        sm->setMaterialName(materialName);
880        // bool useSharedVertices
881        readBools(stream,&sm->useSharedVertices, 1);
882
883        sm->indexData->indexStart = 0;
884        unsigned int indexCount = 0;
885        readInts(stream, &indexCount, 1);
886        sm->indexData->indexCount = indexCount;
887
888        HardwareIndexBufferSharedPtr ibuf;
889        // bool indexes32Bit
890        bool idx32bit;
891        readBools(stream, &idx32bit, 1);
892        if (idx32bit)
893        {
894            ibuf = HardwareBufferManager::getSingleton().
895                createIndexBuffer(
896                    HardwareIndexBuffer::IT_32BIT,
897                    sm->indexData->indexCount,
898                    pMesh->mIndexBufferUsage,
899                                        pMesh->mIndexBufferShadowBuffer);
900            // unsigned int* faceVertexIndices
901            unsigned int* pIdx = static_cast<unsigned int*>(
902                ibuf->lock(HardwareBuffer::HBL_DISCARD)
903                );
904            readInts(stream, pIdx, sm->indexData->indexCount);
905            ibuf->unlock();
906
907        }
908        else // 16-bit
909        {
910            ibuf = HardwareBufferManager::getSingleton().
911                createIndexBuffer(
912                    HardwareIndexBuffer::IT_16BIT,
913                    sm->indexData->indexCount,
914                    pMesh->mIndexBufferUsage,
915                                        pMesh->mIndexBufferShadowBuffer);
916            // unsigned short* faceVertexIndices
917            unsigned short* pIdx = static_cast<unsigned short*>(
918                ibuf->lock(HardwareBuffer::HBL_DISCARD)
919                );
920            readShorts(stream, pIdx, sm->indexData->indexCount);
921            ibuf->unlock();
922        }
923        sm->indexData->indexBuffer = ibuf;
924
925        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
926        if (!sm->useSharedVertices)
927        {
928            streamID = readChunk(stream);
929            if (streamID != M_GEOMETRY)
930            {
931                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file",
932                    "MeshSerializerImpl::readSubMesh");
933            }
934            sm->vertexData = new VertexData();
935            readGeometry(stream, pMesh, sm->vertexData);
936        }
937
938
939        // Find all bone assignments, submesh operation, and texture aliases (if present)
940        if (!stream->eof())
941        {
942            streamID = readChunk(stream);
943            while(!stream->eof() &&
944                (streamID == M_SUBMESH_BONE_ASSIGNMENT ||
945                 streamID == M_SUBMESH_OPERATION ||
946                 streamID == M_SUBMESH_TEXTURE_ALIAS))
947            {
948                switch(streamID)
949                {
950                case M_SUBMESH_OPERATION:
951                    readSubMeshOperation(stream, pMesh, sm);
952                    break;
953                case M_SUBMESH_BONE_ASSIGNMENT:
954                    readSubMeshBoneAssignment(stream, pMesh, sm);
955                    break;
956                case M_SUBMESH_TEXTURE_ALIAS:
957                    readSubMeshTextureAlias(stream, pMesh, sm);
958                    break;
959                }
960
961                if (!stream->eof())
962                {
963                    streamID = readChunk(stream);
964                }
965
966            }
967            if (!stream->eof())
968            {
969                // Backpedal back to start of stream
970                stream->skip(-STREAM_OVERHEAD_SIZE);
971            }
972        }
973
974
975    }
976    //---------------------------------------------------------------------
977    void MeshSerializerImpl::readSubMeshOperation(DataStreamPtr& stream,
978        Mesh* pMesh, SubMesh* sm)
979    {
980        // unsigned short operationType
981        unsigned short opType;
982        readShorts(stream, &opType, 1);
983        sm->operationType = static_cast<RenderOperation::OperationType>(opType);
984    }
985    //---------------------------------------------------------------------
986    void MeshSerializerImpl::readSubMeshTextureAlias(DataStreamPtr& stream, Mesh* pMesh, SubMesh* sub)
987    {
988        String aliasName = readString(stream);
989        String textureName = readString(stream);
990        sub->addTextureAlias(aliasName, textureName);
991    }
992    //---------------------------------------------------------------------
993    void MeshSerializerImpl::writeSkeletonLink(const String& skelName)
994    {
995        writeChunkHeader(M_MESH_SKELETON_LINK, calcSkeletonLinkSize(skelName));
996
997        writeString(skelName);
998
999    }
1000    //---------------------------------------------------------------------
1001    void MeshSerializerImpl::readSkeletonLink(DataStreamPtr& stream, Mesh* pMesh)
1002    {
1003        String skelName = readString(stream);
1004        pMesh->setSkeletonName(skelName);
1005    }
1006    //---------------------------------------------------------------------
1007    void MeshSerializerImpl::readTextureLayer(DataStreamPtr& stream, Mesh* pMesh,
1008        MaterialPtr& pMat)
1009    {
1010        // Material definition section phased out of 1.1
1011    }
1012    //---------------------------------------------------------------------
1013    size_t MeshSerializerImpl::calcSkeletonLinkSize(const String& skelName)
1014    {
1015        size_t size = STREAM_OVERHEAD_SIZE;
1016
1017        size += skelName.length() + 1;
1018
1019        return size;
1020
1021    }
1022    //---------------------------------------------------------------------
1023    void MeshSerializerImpl::writeMeshBoneAssignment(const VertexBoneAssignment& assign)
1024    {
1025        writeChunkHeader(M_MESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
1026
1027        // unsigned int vertexIndex;
1028        writeInts(&(assign.vertexIndex), 1);
1029        // unsigned short boneIndex;
1030        writeShorts(&(assign.boneIndex), 1);
1031        // float weight;
1032        writeFloats(&(assign.weight), 1);
1033    }
1034    //---------------------------------------------------------------------
1035    void MeshSerializerImpl::writeSubMeshBoneAssignment(const VertexBoneAssignment& assign)
1036    {
1037        writeChunkHeader(M_SUBMESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
1038
1039        // unsigned int vertexIndex;
1040        writeInts(&(assign.vertexIndex), 1);
1041        // unsigned short boneIndex;
1042        writeShorts(&(assign.boneIndex), 1);
1043        // float weight;
1044        writeFloats(&(assign.weight), 1);
1045    }
1046    //---------------------------------------------------------------------
1047    void MeshSerializerImpl::readMeshBoneAssignment(DataStreamPtr& stream, Mesh* pMesh)
1048    {
1049        VertexBoneAssignment assign;
1050
1051        // unsigned int vertexIndex;
1052        readInts(stream, &(assign.vertexIndex),1);
1053        // unsigned short boneIndex;
1054        readShorts(stream, &(assign.boneIndex),1);
1055        // float weight;
1056        readFloats(stream, &(assign.weight), 1);
1057
1058        pMesh->addBoneAssignment(assign);
1059
1060    }
1061    //---------------------------------------------------------------------
1062    void MeshSerializerImpl::readSubMeshBoneAssignment(DataStreamPtr& stream,
1063        Mesh* pMesh, SubMesh* sub)
1064    {
1065        VertexBoneAssignment assign;
1066
1067        // unsigned int vertexIndex;
1068        readInts(stream, &(assign.vertexIndex),1);
1069        // unsigned short boneIndex;
1070        readShorts(stream, &(assign.boneIndex),1);
1071        // float weight;
1072        readFloats(stream, &(assign.weight), 1);
1073
1074        sub->addBoneAssignment(assign);
1075
1076    }
1077    //---------------------------------------------------------------------
1078    size_t MeshSerializerImpl::calcBoneAssignmentSize(void)
1079    {
1080        size_t size = STREAM_OVERHEAD_SIZE;
1081
1082        // Vert index
1083        size += sizeof(unsigned int);
1084        // Bone index
1085        size += sizeof(unsigned short);
1086        // weight
1087        size += sizeof(float);
1088
1089        return size;
1090    }
1091    //---------------------------------------------------------------------
1092    void MeshSerializerImpl::writeLodInfo(const Mesh* pMesh)
1093    {
1094        unsigned short numLods = pMesh->getNumLodLevels();
1095        bool manual = pMesh->isLodManual();
1096        writeLodSummary(numLods, manual);
1097
1098                // Loop from LOD 1 (not 0, this is full detail)
1099        for (unsigned short i = 1; i < numLods; ++i)
1100        {
1101                        const MeshLodUsage& usage = pMesh->getLodLevel(i);
1102                        if (manual)
1103                        {
1104                                writeLodUsageManual(usage);
1105                        }
1106                        else
1107                        {
1108                                writeLodUsageGenerated(pMesh, usage, i);
1109                        }
1110
1111        }
1112
1113
1114    }
1115    //---------------------------------------------------------------------
1116    void MeshSerializerImpl::writeLodSummary(unsigned short numLevels, bool manual)
1117    {
1118        // Header
1119        size_t size = STREAM_OVERHEAD_SIZE;
1120        // unsigned short numLevels;
1121        size += sizeof(unsigned short);
1122        // bool manual;  (true for manual alternate meshes, false for generated)
1123        size += sizeof(bool);
1124        writeChunkHeader(M_MESH_LOD, size);
1125
1126        // Details
1127        // unsigned short numLevels;
1128        writeShorts(&numLevels, 1);
1129        // bool manual;  (true for manual alternate meshes, false for generated)
1130        writeBools(&manual, 1);
1131
1132
1133    }
1134    //---------------------------------------------------------------------
1135    void MeshSerializerImpl::writeLodUsageManual(const MeshLodUsage& usage)
1136    {
1137        // Header
1138        size_t size = STREAM_OVERHEAD_SIZE;
1139        size_t manualSize = STREAM_OVERHEAD_SIZE;
1140        // float fromDepthSquared;
1141        size += sizeof(float);
1142        // Manual part size
1143
1144        // String manualMeshName;
1145        manualSize += usage.manualName.length() + 1;
1146
1147        size += manualSize;
1148
1149        writeChunkHeader(M_MESH_LOD_USAGE, size);
1150        writeFloats(&(usage.fromDepthSquared), 1);
1151
1152        writeChunkHeader(M_MESH_LOD_MANUAL, manualSize);
1153        writeString(usage.manualName);
1154
1155
1156    }
1157    //---------------------------------------------------------------------
1158    void MeshSerializerImpl::writeLodUsageGenerated(const Mesh* pMesh, const MeshLodUsage& usage,
1159                unsigned short lodNum)
1160    {
1161                // Usage Header
1162        size_t size = STREAM_OVERHEAD_SIZE;
1163                unsigned short subidx;
1164
1165        // float fromDepthSquared;
1166        size += sizeof(float);
1167
1168        // Calc generated SubMesh sections size
1169                for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
1170                {
1171                        // header
1172                        size += STREAM_OVERHEAD_SIZE;
1173                        // unsigned int numFaces;
1174                        size += sizeof(unsigned int);
1175                        SubMesh* sm = pMesh->getSubMesh(subidx);
1176            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1177
1178            // bool indexes32Bit
1179                        size += sizeof(bool);
1180                        // unsigned short*/int* faceIndexes;
1181            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
1182            {
1183                            size += static_cast<unsigned long>(
1184                    sizeof(unsigned int) * indexData->indexCount);
1185            }
1186            else
1187            {
1188                            size += static_cast<unsigned long>(
1189                    sizeof(unsigned short) * indexData->indexCount);
1190            }
1191
1192                }
1193
1194        writeChunkHeader(M_MESH_LOD_USAGE, size);
1195        writeFloats(&(usage.fromDepthSquared), 1);
1196
1197                // Now write sections
1198        // Calc generated SubMesh sections size
1199                for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
1200                {
1201                        size = STREAM_OVERHEAD_SIZE;
1202                        // unsigned int numFaces;
1203                        size += sizeof(unsigned int);
1204                        SubMesh* sm = pMesh->getSubMesh(subidx);
1205            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1206            // bool indexes32Bit
1207                        size += sizeof(bool);
1208                        // unsigned short*/int* faceIndexes;
1209            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
1210            {
1211                            size += static_cast<unsigned long>(
1212                    sizeof(unsigned int) * indexData->indexCount);
1213            }
1214            else
1215            {
1216                            size += static_cast<unsigned long>(
1217                    sizeof(unsigned short) * indexData->indexCount);
1218            }
1219
1220                        writeChunkHeader(M_MESH_LOD_GENERATED, size);
1221                        unsigned int idxCount = static_cast<unsigned int>(indexData->indexCount);
1222                        writeInts(&idxCount, 1);
1223            // Lock index buffer to write
1224            HardwareIndexBufferSharedPtr ibuf = indexData->indexBuffer;
1225                        // bool indexes32bit
1226                        bool idx32 = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
1227                        writeBools(&idx32, 1);
1228            if (idx32)
1229            {
1230                unsigned int* pIdx = static_cast<unsigned int*>(
1231                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
1232                            writeInts(pIdx, indexData->indexCount);
1233                ibuf->unlock();
1234            }
1235            else
1236            {
1237                unsigned short* pIdx = static_cast<unsigned short*>(
1238                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
1239                            writeShorts(pIdx, indexData->indexCount);
1240                ibuf->unlock();
1241            }
1242                }
1243
1244
1245    }
1246    //---------------------------------------------------------------------
1247    void MeshSerializerImpl::writeBoundsInfo(const Mesh* pMesh)
1248    {
1249                // Usage Header
1250        unsigned long size = STREAM_OVERHEAD_SIZE;
1251
1252        size += sizeof(float) * 7;
1253        writeChunkHeader(M_MESH_BOUNDS, size);
1254
1255        // float minx, miny, minz
1256        const Vector3& min = pMesh->mAABB.getMinimum();
1257        const Vector3& max = pMesh->mAABB.getMaximum();
1258        writeFloats(&min.x, 1);
1259        writeFloats(&min.y, 1);
1260        writeFloats(&min.z, 1);
1261        // float maxx, maxy, maxz
1262        writeFloats(&max.x, 1);
1263        writeFloats(&max.y, 1);
1264        writeFloats(&max.z, 1);
1265        // float radius
1266        writeFloats(&pMesh->mBoundRadius, 1);
1267
1268    }
1269    //---------------------------------------------------------------------
1270    void MeshSerializerImpl::readBoundsInfo(DataStreamPtr& stream, Mesh* pMesh)
1271    {
1272        Vector3 min, max;
1273        // float minx, miny, minz
1274        readFloats(stream, &min.x, 1);
1275        readFloats(stream, &min.y, 1);
1276        readFloats(stream, &min.z, 1);
1277        // float maxx, maxy, maxz
1278        readFloats(stream, &max.x, 1);
1279        readFloats(stream, &max.y, 1);
1280        readFloats(stream, &max.z, 1);
1281        AxisAlignedBox box(min, max);
1282        pMesh->_setBounds(box, true);
1283        // float radius
1284        float radius;
1285        readFloats(stream, &radius, 1);
1286        pMesh->_setBoundingSphereRadius(radius);
1287
1288
1289
1290    }
1291    //---------------------------------------------------------------------
1292        void MeshSerializerImpl::readMeshLodInfo(DataStreamPtr& stream, Mesh* pMesh)
1293        {
1294                unsigned short streamID, i;
1295
1296        // unsigned short numLevels;
1297                readShorts(stream, &(pMesh->mNumLods), 1);
1298        // bool manual;  (true for manual alternate meshes, false for generated)
1299                readBools(stream, &(pMesh->mIsLodManual), 1);
1300
1301                // Preallocate submesh lod face data if not manual
1302                if (!pMesh->mIsLodManual)
1303                {
1304                        unsigned short numsubs = pMesh->getNumSubMeshes();
1305                        for (i = 0; i < numsubs; ++i)
1306                        {
1307                                SubMesh* sm = pMesh->getSubMesh(i);
1308                                sm->mLodFaceList.resize(pMesh->mNumLods-1);
1309                        }
1310                }
1311
1312                // Loop from 1 rather than 0 (full detail index is not in file)
1313                for (i = 1; i < pMesh->mNumLods; ++i)
1314                {
1315                        streamID = readChunk(stream);
1316                        if (streamID != M_MESH_LOD_USAGE)
1317                        {
1318                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1319                                        "Missing M_MESH_LOD_USAGE stream in " + pMesh->getName(),
1320                                        "MeshSerializerImpl::readMeshLodInfo");
1321                        }
1322                        // Read depth
1323                        MeshLodUsage usage;
1324                        readFloats(stream, &(usage.fromDepthSquared), 1);
1325
1326                        if (pMesh->isLodManual())
1327                        {
1328                                readMeshLodUsageManual(stream, pMesh, i, usage);
1329                        }
1330                        else //(!pMesh->isLodManual)
1331                        {
1332                                readMeshLodUsageGenerated(stream, pMesh, i, usage);
1333                        }
1334            usage.edgeData = NULL;
1335
1336                        // Save usage
1337                        pMesh->mMeshLodUsageList.push_back(usage);
1338                }
1339
1340
1341        }
1342    //---------------------------------------------------------------------
1343        void MeshSerializerImpl::readMeshLodUsageManual(DataStreamPtr& stream,
1344        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
1345        {
1346                unsigned long streamID;
1347                // Read detail stream
1348                streamID = readChunk(stream);
1349                if (streamID != M_MESH_LOD_MANUAL)
1350                {
1351                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1352                                "Missing M_MESH_LOD_MANUAL stream in " + pMesh->getName(),
1353                                "MeshSerializerImpl::readMeshLodUsageManual");
1354                }
1355
1356                usage.manualName = readString(stream);
1357                usage.manualMesh.setNull(); // will trigger load later
1358        }
1359    //---------------------------------------------------------------------
1360        void MeshSerializerImpl::readMeshLodUsageGenerated(DataStreamPtr& stream,
1361        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
1362        {
1363                usage.manualName = "";
1364                usage.manualMesh.setNull();
1365
1366                // Get one set of detail per SubMesh
1367                unsigned short numSubs, i;
1368                unsigned long streamID;
1369                numSubs = pMesh->getNumSubMeshes();
1370                for (i = 0; i < numSubs; ++i)
1371                {
1372                        streamID = readChunk(stream);
1373                        if (streamID != M_MESH_LOD_GENERATED)
1374                        {
1375                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1376                                        "Missing M_MESH_LOD_GENERATED stream in " + pMesh->getName(),
1377                                        "MeshSerializerImpl::readMeshLodUsageGenerated");
1378                        }
1379
1380                        SubMesh* sm = pMesh->getSubMesh(i);
1381                        // lodNum - 1 because SubMesh doesn't store full detail LOD
1382            sm->mLodFaceList[lodNum - 1] = new IndexData();
1383                        IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1384            // unsigned int numIndexes
1385            unsigned int numIndexes;
1386                        readInts(stream, &numIndexes, 1);
1387            indexData->indexCount = static_cast<size_t>(numIndexes);
1388            // bool indexes32Bit
1389            bool idx32Bit;
1390            readBools(stream, &idx32Bit, 1);
1391            // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
1392            if (idx32Bit)
1393            {
1394                indexData->indexBuffer = HardwareBufferManager::getSingleton().
1395                    createIndexBuffer(HardwareIndexBuffer::IT_32BIT, indexData->indexCount,
1396                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
1397                unsigned int* pIdx = static_cast<unsigned int*>(
1398                    indexData->indexBuffer->lock(
1399                        0,
1400                        indexData->indexBuffer->getSizeInBytes(),
1401                        HardwareBuffer::HBL_DISCARD) );
1402
1403                            readInts(stream, pIdx, indexData->indexCount);
1404                indexData->indexBuffer->unlock();
1405
1406            }
1407            else
1408            {
1409                indexData->indexBuffer = HardwareBufferManager::getSingleton().
1410                    createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
1411                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
1412                unsigned short* pIdx = static_cast<unsigned short*>(
1413                    indexData->indexBuffer->lock(
1414                        0,
1415                        indexData->indexBuffer->getSizeInBytes(),
1416                        HardwareBuffer::HBL_DISCARD) );
1417                            readShorts(stream, pIdx, indexData->indexCount);
1418                indexData->indexBuffer->unlock();
1419
1420            }
1421
1422                }
1423        }
1424    //---------------------------------------------------------------------
1425    void MeshSerializerImpl::flipFromLittleEndian(void* pData, size_t vertexCount,
1426        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1427        {
1428                if (mFlipEndian)
1429                {
1430                flipEndian(pData, vertexCount, vertexSize, elems);
1431                }
1432    }
1433    //---------------------------------------------------------------------
1434    void MeshSerializerImpl::flipToLittleEndian(void* pData, size_t vertexCount,
1435                        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1436        {
1437                if (mFlipEndian)
1438                {
1439                flipEndian(pData, vertexCount, vertexSize, elems);
1440                }
1441        }
1442    //---------------------------------------------------------------------
1443    void MeshSerializerImpl::flipEndian(void* pData, size_t vertexCount,
1444        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1445        {
1446                void *pBase = pData;
1447                for (size_t v = 0; v < vertexCount; ++v)
1448                {
1449                        VertexDeclaration::VertexElementList::const_iterator ei, eiend;
1450                        eiend = elems.end();
1451                        for (ei = elems.begin(); ei != eiend; ++ei)
1452                        {
1453                                void *pElem;
1454                                // re-base pointer to the element
1455                                (*ei).baseVertexPointerToElement(pBase, &pElem);
1456                                // Flip the endian based on the type
1457                                size_t typeSize = 0;
1458                                switch (VertexElement::getBaseType((*ei).getType()))
1459                                {
1460                                        case VET_FLOAT1:
1461                                                typeSize = sizeof(float);
1462                                                break;
1463                                        case VET_SHORT1:
1464                                                typeSize = sizeof(short);
1465                                                break;
1466                                        case VET_COLOUR:
1467                                        case VET_COLOUR_ABGR:
1468                                        case VET_COLOUR_ARGB:
1469                                                typeSize = sizeof(RGBA);
1470                                                break;
1471                                        case VET_UBYTE4:
1472                                                typeSize = 0; // NO FLIPPING
1473                                                break;
1474                                };
1475                Serializer::flipEndian(pElem, typeSize,
1476                                        VertexElement::getTypeCount((*ei).getType()));
1477
1478                        }
1479
1480                        pBase = static_cast<void*>(
1481                                static_cast<unsigned char*>(pBase) + vertexSize);
1482
1483                }
1484        }
1485    //---------------------------------------------------------------------
1486        size_t MeshSerializerImpl::calcEdgeListSize(const Mesh* pMesh)
1487        {
1488        size_t size = STREAM_OVERHEAD_SIZE;
1489
1490        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
1491        {
1492
1493            const EdgeData* edgeData = pMesh->getEdgeList(i);
1494            bool isManual = pMesh->isLodManual() && (i > 0);
1495
1496            size += calcEdgeListLodSize(edgeData, isManual);
1497
1498        }
1499
1500        return size;
1501        }
1502    //---------------------------------------------------------------------
1503    size_t MeshSerializerImpl::calcEdgeListLodSize(const EdgeData* edgeData, bool isManual)
1504    {
1505        size_t size = STREAM_OVERHEAD_SIZE;
1506
1507        // unsigned short lodIndex
1508        size += sizeof(uint16);
1509
1510        // bool isManual                        // If manual, no edge data here, loaded from manual mesh
1511        size += sizeof(bool);
1512        if (!isManual)
1513        {
1514            // unsigned long numTriangles
1515            size += sizeof(uint32);
1516            // unsigned long numEdgeGroups
1517            size += sizeof(uint32);
1518            // Triangle* triangleList
1519            size_t triSize = 0;
1520            // unsigned long indexSet
1521            // unsigned long vertexSet
1522            // unsigned long vertIndex[3]
1523            // unsigned long sharedVertIndex[3]
1524            // float normal[4]
1525            triSize += sizeof(uint32) * 8
1526                    + sizeof(float) * 4;
1527
1528            size += triSize * edgeData->triangles.size();
1529            // Write the groups
1530            for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
1531                gi != edgeData->edgeGroups.end(); ++gi)
1532            {
1533                const EdgeData::EdgeGroup& edgeGroup = *gi;
1534                size += calcEdgeGroupSize(edgeGroup);
1535            }
1536
1537        }
1538
1539        return size;
1540    }
1541    //---------------------------------------------------------------------
1542    size_t MeshSerializerImpl::calcEdgeGroupSize(const EdgeData::EdgeGroup& group)
1543    {
1544        size_t size = STREAM_OVERHEAD_SIZE;
1545
1546        // unsigned long vertexSet
1547        size += sizeof(uint32);
1548        // unsigned long numEdges
1549        size += sizeof(uint32);
1550        // Edge* edgeList
1551        size_t edgeSize = 0;
1552        // unsigned long  triIndex[2]
1553        // unsigned long  vertIndex[2]
1554        // unsigned long  sharedVertIndex[2]
1555        // bool degenerate
1556        edgeSize += sizeof(uint32) * 6 + sizeof(bool);
1557        size += edgeSize * group.edges.size();
1558
1559        return size;
1560    }
1561    //---------------------------------------------------------------------
1562        void MeshSerializerImpl::writeEdgeList(const Mesh* pMesh)
1563        {
1564        writeChunkHeader(M_EDGE_LISTS, calcEdgeListSize(pMesh));
1565
1566        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
1567        {
1568            const EdgeData* edgeData = pMesh->getEdgeList(i);
1569            bool isManual = pMesh->isLodManual() && (i > 0);
1570            writeChunkHeader(M_EDGE_LIST_LOD, calcEdgeListLodSize(edgeData, isManual));
1571
1572            // unsigned short lodIndex
1573            writeShorts(&i, 1);
1574
1575            // bool isManual                    // If manual, no edge data here, loaded from manual mesh
1576            writeBools(&isManual, 1);
1577            if (!isManual)
1578            {
1579                // unsigned long  numTriangles
1580                uint32 count = static_cast<uint32>(edgeData->triangles.size());
1581                writeInts(&count, 1);
1582                // unsigned long numEdgeGroups
1583                count = static_cast<uint32>(edgeData->edgeGroups.size());
1584                writeInts(&count, 1);
1585                // Triangle* triangleList
1586                // Iterate rather than writing en-masse to allow endian conversion
1587                for (EdgeData::TriangleList::const_iterator t = edgeData->triangles.begin();
1588                    t != edgeData->triangles.end(); ++t)
1589                {
1590                    const EdgeData::Triangle& tri = *t;
1591                    // unsigned long indexSet;
1592                    uint32 tmp[3];
1593                    tmp[0] = tri.indexSet;
1594                    writeInts(tmp, 1);
1595                    // unsigned long vertexSet;
1596                    tmp[0] = tri.vertexSet;
1597                    writeInts(tmp, 1);
1598                    // unsigned long vertIndex[3];
1599                    tmp[0] = tri.vertIndex[0];
1600                    tmp[1] = tri.vertIndex[1];
1601                    tmp[2] = tri.vertIndex[2];
1602                    writeInts(tmp, 3);
1603                    // unsigned long sharedVertIndex[3];
1604                    tmp[0] = tri.sharedVertIndex[0];
1605                    tmp[1] = tri.sharedVertIndex[1];
1606                    tmp[2] = tri.sharedVertIndex[2];
1607                    writeInts(tmp, 3);
1608                    // float normal[4];
1609                    writeFloats(&(tri.normal.x), 4);
1610
1611                }
1612                // Write the groups
1613                for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
1614                    gi != edgeData->edgeGroups.end(); ++gi)
1615                {
1616                    const EdgeData::EdgeGroup& edgeGroup = *gi;
1617                    writeChunkHeader(M_EDGE_GROUP, calcEdgeGroupSize(edgeGroup));
1618                    // unsigned long vertexSet
1619                    uint32 vertexSet = static_cast<uint32>(edgeGroup.vertexSet);
1620                    writeInts(&vertexSet, 1);
1621                    // unsigned long numEdges
1622                    count = static_cast<uint32>(edgeGroup.edges.size());
1623                    writeInts(&count, 1);
1624                    // Edge* edgeList
1625                    // Iterate rather than writing en-masse to allow endian conversion
1626                    for (EdgeData::EdgeList::const_iterator ei = edgeGroup.edges.begin();
1627                        ei != edgeGroup.edges.end(); ++ei)
1628                    {
1629                        const EdgeData::Edge& edge = *ei;
1630                        uint32 tmp[2];
1631                        // unsigned long  triIndex[2]
1632                        tmp[0] = edge.triIndex[0];
1633                        tmp[1] = edge.triIndex[1];
1634                        writeInts(tmp, 2);
1635                        // unsigned long  vertIndex[2]
1636                        tmp[0] = edge.vertIndex[0];
1637                        tmp[1] = edge.vertIndex[1];
1638                        writeInts(tmp, 2);
1639                        // unsigned long  sharedVertIndex[2]
1640                        tmp[0] = edge.sharedVertIndex[0];
1641                        tmp[1] = edge.sharedVertIndex[1];
1642                        writeInts(tmp, 2);
1643                        // bool degenerate
1644                        writeBools(&(edge.degenerate), 1);
1645                    }
1646
1647                }
1648
1649            }
1650
1651        }
1652        }
1653    //---------------------------------------------------------------------
1654        void MeshSerializerImpl::readEdgeList(DataStreamPtr& stream, Mesh* pMesh)
1655        {
1656        unsigned short streamID;
1657
1658        if (!stream->eof())
1659        {
1660            streamID = readChunk(stream);
1661            while(!stream->eof() &&
1662                streamID == M_EDGE_LIST_LOD)
1663            {
1664                // Process single LOD
1665
1666                // unsigned short lodIndex
1667                unsigned short lodIndex;
1668                readShorts(stream, &lodIndex, 1);
1669
1670                // bool isManual                        // If manual, no edge data here, loaded from manual mesh
1671                bool isManual;
1672                readBools(stream, &isManual, 1);
1673                // Only load in non-manual levels; others will be connected up by Mesh on demand
1674                if (!isManual)
1675                {
1676                    MeshLodUsage& usage = const_cast<MeshLodUsage&>(pMesh->getLodLevel(lodIndex));
1677
1678                    usage.edgeData = new EdgeData();
1679                    // unsigned long numTriangles
1680                    uint32 numTriangles;
1681                    readInts(stream, &numTriangles, 1);
1682                    // Allocate correct amount of memory
1683                    usage.edgeData->triangles.resize(numTriangles);
1684                    // unsigned long numEdgeGroups
1685                    uint32 numEdgeGroups;
1686                    readInts(stream, &numEdgeGroups, 1);
1687                    // Allocate correct amount of memory
1688                    usage.edgeData->edgeGroups.resize(numEdgeGroups);
1689                    // Triangle* triangleList
1690                    uint32 tmp[3];
1691                    for (size_t t = 0; t < numTriangles; ++t)
1692                    {
1693                        EdgeData::Triangle& tri = usage.edgeData->triangles[t];
1694                        // unsigned long indexSet
1695                        readInts(stream, tmp, 1);
1696                        tri.indexSet = tmp[0];
1697                        // unsigned long vertexSet
1698                        readInts(stream, tmp, 1);
1699                        tri.vertexSet = tmp[0];
1700                        // unsigned long vertIndex[3]
1701                        readInts(stream, tmp, 3);
1702                        tri.vertIndex[0] = tmp[0];
1703                        tri.vertIndex[1] = tmp[1];
1704                        tri.vertIndex[2] = tmp[2];
1705                        // unsigned long sharedVertIndex[3]
1706                        readInts(stream, tmp, 3);
1707                        tri.sharedVertIndex[0] = tmp[0];
1708                        tri.sharedVertIndex[1] = tmp[1];
1709                        tri.sharedVertIndex[2] = tmp[2];
1710                        // float normal[4]
1711                        readFloats(stream, &(tri.normal.x), 4);
1712
1713                    }
1714
1715                    for (uint32 eg = 0; eg < numEdgeGroups; ++eg)
1716                    {
1717                        streamID = readChunk(stream);
1718                        if (streamID != M_EDGE_GROUP)
1719                        {
1720                            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1721                                "Missing M_EDGE_GROUP stream",
1722                                "MeshSerializerImpl::readEdgeList");
1723                        }
1724                        EdgeData::EdgeGroup& edgeGroup = usage.edgeData->edgeGroups[eg];
1725
1726                        // unsigned long vertexSet
1727                        readInts(stream, tmp, 1);
1728                        edgeGroup.vertexSet = tmp[0];
1729                        // unsigned long numEdges
1730                        uint32 numEdges;
1731                        readInts(stream, &numEdges, 1);
1732                        edgeGroup.edges.resize(numEdges);
1733                        // Edge* edgeList
1734                        for (uint32 e = 0; e < numEdges; ++e)
1735                        {
1736                            EdgeData::Edge& edge = edgeGroup.edges[e];
1737                            // unsigned long  triIndex[2]
1738                            readInts(stream, tmp, 2);
1739                            edge.triIndex[0] = tmp[0];
1740                            edge.triIndex[1] = tmp[1];
1741                            // unsigned long  vertIndex[2]
1742                            readInts(stream, tmp, 2);
1743                            edge.vertIndex[0] = tmp[0];
1744                            edge.vertIndex[1] = tmp[1];
1745                            // unsigned long  sharedVertIndex[2]
1746                            readInts(stream, tmp, 2);
1747                            edge.sharedVertIndex[0] = tmp[0];
1748                            edge.sharedVertIndex[1] = tmp[1];
1749                            // bool degenerate
1750                            readBools(stream, &(edge.degenerate), 1);
1751                        }
1752                        // Populate edgeGroup.vertexData pointers
1753                        // If there is shared vertex data, vertexSet 0 is that,
1754                        // otherwise 0 is first dedicated
1755                        if (pMesh->sharedVertexData)
1756                        {
1757                            if (edgeGroup.vertexSet == 0)
1758                            {
1759                                edgeGroup.vertexData = pMesh->sharedVertexData;
1760                            }
1761                            else
1762                            {
1763                                edgeGroup.vertexData = pMesh->getSubMesh(
1764                                    edgeGroup.vertexSet-1)->vertexData;
1765                            }
1766                        }
1767                        else
1768                        {
1769                            edgeGroup.vertexData = pMesh->getSubMesh(
1770                                edgeGroup.vertexSet)->vertexData;
1771                        }
1772                    }
1773
1774                }
1775
1776                if (!stream->eof())
1777                {
1778                    streamID = readChunk(stream);
1779                }
1780
1781            }
1782            if (!stream->eof())
1783            {
1784                // Backpedal back to start of stream
1785                stream->skip(-STREAM_OVERHEAD_SIZE);
1786            }
1787        }
1788
1789
1790
1791        pMesh->mEdgeListsBuilt = true;
1792        }
1793        //---------------------------------------------------------------------
1794        size_t MeshSerializerImpl::calcAnimationsSize(const Mesh* pMesh)
1795        {
1796                size_t size = STREAM_OVERHEAD_SIZE;
1797
1798                for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
1799                {
1800                        Animation* anim = pMesh->getAnimation(a);
1801                        size += calcAnimationSize(anim);
1802                }
1803                return size;
1804
1805        }
1806        //---------------------------------------------------------------------
1807        size_t MeshSerializerImpl::calcAnimationSize(const Animation* anim)
1808        {
1809                size_t size = STREAM_OVERHEAD_SIZE;
1810                // char* name
1811                size += anim->getName().length() + 1;
1812
1813                // float length
1814                size += sizeof(float);
1815
1816                Animation::VertexTrackIterator trackIt = anim->getVertexTrackIterator();
1817                while (trackIt.hasMoreElements())
1818                {
1819                        VertexAnimationTrack* vt = trackIt.getNext();
1820                        size += calcAnimationTrackSize(vt);
1821                }
1822
1823                return size;
1824        }
1825        //---------------------------------------------------------------------
1826        size_t MeshSerializerImpl::calcAnimationTrackSize(const VertexAnimationTrack* track)
1827        {
1828                size_t size = STREAM_OVERHEAD_SIZE;
1829                // uint16 type
1830                size += sizeof(uint16);
1831                // unsigned short target                // 0 for shared geometry,
1832                size += sizeof(unsigned short);
1833
1834                if (track->getAnimationType() == VAT_MORPH)
1835                {
1836                        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
1837                        {
1838                                VertexMorphKeyFrame* kf = track->getVertexMorphKeyFrame(i);
1839                                size += calcMorphKeyframeSize(kf, track->getAssociatedVertexData()->vertexCount);
1840                        }
1841                }
1842                else
1843                {
1844                        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
1845                        {
1846                                VertexPoseKeyFrame* kf = track->getVertexPoseKeyFrame(i);
1847                                size += calcPoseKeyframeSize(kf);
1848                        }
1849                }
1850                return size;
1851        }
1852        //---------------------------------------------------------------------
1853        size_t MeshSerializerImpl::calcMorphKeyframeSize(const VertexMorphKeyFrame* kf,
1854                size_t vertexCount)
1855        {
1856                size_t size = STREAM_OVERHEAD_SIZE;
1857                // float time
1858                size += sizeof(float);
1859                // bool isOriginalGeometry  // point at original geometry?
1860                size += sizeof(bool);
1861                // float x,y,z
1862                size += sizeof(float) * 3 * vertexCount;
1863
1864                return size;
1865        }
1866        //---------------------------------------------------------------------
1867        size_t MeshSerializerImpl::calcPoseKeyframeSize(const VertexPoseKeyFrame* kf)
1868        {
1869                size_t size = STREAM_OVERHEAD_SIZE;
1870
1871                // float time
1872                size += sizeof(float);
1873
1874                size += calcPoseKeyframePoseRefSize() * kf->getPoseReferences().size();
1875
1876                return size;
1877
1878        }
1879        //---------------------------------------------------------------------
1880        size_t MeshSerializerImpl::calcPoseKeyframePoseRefSize(void)
1881        {
1882                size_t size = STREAM_OVERHEAD_SIZE;
1883                // unsigned short poseIndex
1884                size += sizeof(uint16);
1885                // float influence
1886                size += sizeof(float);
1887
1888                return size;
1889
1890        }
1891        //---------------------------------------------------------------------
1892        size_t MeshSerializerImpl::calcPosesSize(const Mesh* pMesh)
1893        {
1894                size_t size = STREAM_OVERHEAD_SIZE;
1895
1896                Mesh::ConstPoseIterator poseIt = pMesh->getPoseIterator();
1897                while (poseIt.hasMoreElements())
1898                {
1899                        size += calcPoseSize(poseIt.getNext());
1900                }
1901                return size;
1902        }
1903        //---------------------------------------------------------------------
1904        size_t MeshSerializerImpl::calcPoseSize(const Pose* pose)
1905        {
1906                size_t size = STREAM_OVERHEAD_SIZE;
1907
1908                // char* name (may be blank)
1909                size += pose->getName().length() + 1;
1910                // unsigned short target
1911                size += sizeof(uint16);
1912
1913                // vertex offsets
1914                size += pose->getVertexOffsets().size() * calcPoseVertexSize();
1915
1916                return size;
1917
1918        }
1919        //---------------------------------------------------------------------
1920        size_t MeshSerializerImpl::calcPoseVertexSize(void)
1921        {
1922                size_t size = STREAM_OVERHEAD_SIZE;
1923                // unsigned long vertexIndex
1924                size += sizeof(uint32);
1925                // float xoffset, yoffset, zoffset
1926                size += sizeof(float) * 3;
1927
1928                return size;
1929        }
1930        //---------------------------------------------------------------------
1931        void MeshSerializerImpl::writePoses(const Mesh* pMesh)
1932        {
1933                Mesh::ConstPoseIterator poseIterator = pMesh->getPoseIterator();
1934                if (poseIterator.hasMoreElements())
1935                {
1936                        writeChunkHeader(M_POSES, calcPosesSize(pMesh));
1937                        while (poseIterator.hasMoreElements())
1938                        {
1939                                writePose(poseIterator.getNext());
1940                        }
1941                }
1942
1943        }
1944        //---------------------------------------------------------------------
1945        void MeshSerializerImpl::writePose(const Pose* pose)
1946        {
1947                writeChunkHeader(M_POSE, calcPoseSize(pose));
1948
1949                // char* name (may be blank)
1950                writeString(pose->getName());
1951
1952                // unsigned short target
1953                ushort val = pose->getTarget();
1954                writeShorts(&val, 1);
1955
1956                size_t vertexSize = calcPoseVertexSize();
1957                Pose::ConstVertexOffsetIterator vit = pose->getVertexOffsetIterator();
1958                while (vit.hasMoreElements())
1959                {
1960                        uint32 vertexIndex = (uint32)vit.peekNextKey();
1961                        Vector3 offset = vit.getNext();
1962                        writeChunkHeader(M_POSE_VERTEX, vertexSize);
1963                        // unsigned long vertexIndex
1964                        writeInts(&vertexIndex, 1);
1965                        // float xoffset, yoffset, zoffset
1966                        writeFloats(offset.val, 3);
1967                }
1968
1969
1970        }
1971        //---------------------------------------------------------------------
1972        void MeshSerializerImpl::writeAnimations(const Mesh* pMesh)
1973        {
1974                writeChunkHeader(M_ANIMATIONS, calcAnimationsSize(pMesh));
1975
1976                for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
1977                {
1978                        Animation* anim = pMesh->getAnimation(a);
1979                        LogManager::getSingleton().logMessage("Exporting animation " + anim->getName());
1980                        writeAnimation(anim);
1981                        LogManager::getSingleton().logMessage("Animation exported.");
1982                }
1983        }
1984        //---------------------------------------------------------------------
1985        void MeshSerializerImpl::writeAnimation(const Animation* anim)
1986        {
1987                writeChunkHeader(M_ANIMATION, calcAnimationSize(anim));
1988                // char* name
1989                writeString(anim->getName());
1990                // float length
1991                float len = anim->getLength();
1992                writeFloats(&len, 1);
1993                Animation::VertexTrackIterator trackIt = anim->getVertexTrackIterator();
1994                while (trackIt.hasMoreElements())
1995                {
1996                        VertexAnimationTrack* vt = trackIt.getNext();
1997                        writeAnimationTrack(vt);
1998                }
1999
2000
2001        }
2002    //---------------------------------------------------------------------
2003        void MeshSerializerImpl::writeAnimationTrack(const VertexAnimationTrack* track)
2004        {
2005                writeChunkHeader(M_ANIMATION_TRACK, calcAnimationTrackSize(track));
2006                // unsigned short type                  // 1 == morph, 2 == pose
2007                uint16 animType = (uint16)track->getAnimationType();
2008                writeShorts(&animType, 1);
2009                // unsigned short target
2010                uint16 target = track->getHandle();
2011                writeShorts(&target, 1);
2012
2013                if (track->getAnimationType() == VAT_MORPH)
2014                {
2015                        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
2016                        {
2017                                VertexMorphKeyFrame* kf = track->getVertexMorphKeyFrame(i);
2018                                writeMorphKeyframe(kf, track->getAssociatedVertexData()->vertexCount);
2019                        }
2020                }
2021                else // VAT_POSE
2022                {
2023                        for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
2024                        {
2025                                VertexPoseKeyFrame* kf = track->getVertexPoseKeyFrame(i);
2026                                writePoseKeyframe(kf);
2027                        }
2028                }
2029
2030        }
2031        //---------------------------------------------------------------------
2032        void MeshSerializerImpl::writeMorphKeyframe(const VertexMorphKeyFrame* kf, size_t vertexCount)
2033        {
2034                writeChunkHeader(M_ANIMATION_MORPH_KEYFRAME, calcMorphKeyframeSize(kf, vertexCount));
2035                // float time
2036                float timePos = kf->getTime();
2037                writeFloats(&timePos, 1);
2038                // float x,y,z                  // repeat by number of vertices in original geometry
2039                float* pSrc = static_cast<float*>(
2040                        kf->getVertexBuffer()->lock(HardwareBuffer::HBL_READ_ONLY));
2041                writeFloats(pSrc, vertexCount * 3);
2042                kf->getVertexBuffer()->unlock();
2043        }
2044        //---------------------------------------------------------------------
2045        void MeshSerializerImpl::writePoseKeyframe(const VertexPoseKeyFrame* kf)
2046        {
2047                writeChunkHeader(M_ANIMATION_POSE_KEYFRAME, calcPoseKeyframeSize(kf));
2048                // float time
2049                float timePos = kf->getTime();
2050                writeFloats(&timePos, 1);
2051
2052                // pose references
2053                VertexPoseKeyFrame::ConstPoseRefIterator poseRefIt =
2054                        kf->getPoseReferenceIterator();
2055                while (poseRefIt.hasMoreElements())
2056                {
2057                        writePoseKeyframePoseRef(poseRefIt.getNext());
2058                }
2059
2060
2061
2062        }
2063        //---------------------------------------------------------------------
2064        void MeshSerializerImpl::writePoseKeyframePoseRef(
2065                const VertexPoseKeyFrame::PoseRef& poseRef)
2066        {
2067                writeChunkHeader(M_ANIMATION_POSE_REF, calcPoseKeyframePoseRefSize());
2068                // unsigned short poseIndex
2069                writeShorts(&(poseRef.poseIndex), 1);
2070                // float influence
2071                writeFloats(&(poseRef.influence), 1);
2072        }
2073        //---------------------------------------------------------------------
2074        void MeshSerializerImpl::readPoses(DataStreamPtr& stream, Mesh* pMesh)
2075        {
2076                unsigned short streamID;
2077
2078                // Find all substreams
2079                if (!stream->eof())
2080                {
2081                        streamID = readChunk(stream);
2082                        while(!stream->eof() &&
2083                                (streamID == M_POSE))
2084                        {
2085                                switch(streamID)
2086                                {
2087                                case M_POSE:
2088                                        readPose(stream, pMesh);
2089                                        break;
2090
2091                                }
2092
2093                                if (!stream->eof())
2094                                {
2095                                        streamID = readChunk(stream);
2096                                }
2097
2098                        }
2099                        if (!stream->eof())
2100                        {
2101                                // Backpedal back to start of stream
2102                                stream->skip(-STREAM_OVERHEAD_SIZE);
2103                        }
2104                }
2105        }
2106        //---------------------------------------------------------------------
2107        void MeshSerializerImpl::readPose(DataStreamPtr& stream, Mesh* pMesh)
2108        {
2109                // char* name (may be blank)
2110                String name = readString(stream);
2111                // unsigned short target
2112                unsigned short target;
2113                readShorts(stream, &target, 1);
2114
2115                Pose* pose = pMesh->createPose(target, name);
2116
2117                // Find all substreams
2118                unsigned short streamID;
2119                if (!stream->eof())
2120                {
2121                        streamID = readChunk(stream);
2122                        while(!stream->eof() &&
2123                                (streamID == M_POSE_VERTEX))
2124                        {
2125                                switch(streamID)
2126                                {
2127                                case M_POSE_VERTEX:
2128                                        // create vertex offset
2129                                        uint32 vertIndex;
2130                                        Vector3 offset;
2131                                        // unsigned long vertexIndex
2132                                        readInts(stream, &vertIndex, 1);
2133                                        // float xoffset, yoffset, zoffset
2134                                        readFloats(stream, offset.val, 3);
2135
2136                                        pose->addVertex(vertIndex, offset);
2137                                        break;
2138
2139                                }
2140
2141                                if (!stream->eof())
2142                                {
2143                                        streamID = readChunk(stream);
2144                                }
2145
2146                        }
2147                        if (!stream->eof())
2148                        {
2149                                // Backpedal back to start of stream
2150                                stream->skip(-STREAM_OVERHEAD_SIZE);
2151                        }
2152                }
2153
2154        }
2155        //---------------------------------------------------------------------
2156        void MeshSerializerImpl::readAnimations(DataStreamPtr& stream, Mesh* pMesh)
2157        {
2158                unsigned short streamID;
2159
2160                // Find all substreams
2161                if (!stream->eof())
2162                {
2163                        streamID = readChunk(stream);
2164                        while(!stream->eof() &&
2165                                (streamID == M_ANIMATION))
2166                        {
2167                                switch(streamID)
2168                                {
2169                                case M_ANIMATION:
2170                                        readAnimation(stream, pMesh);
2171                                        break;
2172
2173                                }
2174
2175                                if (!stream->eof())
2176                                {
2177                                        streamID = readChunk(stream);
2178                                }
2179
2180                        }
2181                        if (!stream->eof())
2182                        {
2183                                // Backpedal back to start of stream
2184                                stream->skip(-STREAM_OVERHEAD_SIZE);
2185                        }
2186                }
2187
2188
2189        }
2190        //---------------------------------------------------------------------
2191        void MeshSerializerImpl::readAnimation(DataStreamPtr& stream, Mesh* pMesh)
2192        {
2193
2194                // char* name
2195                String name = readString(stream);
2196                // float length
2197                float len;
2198                readFloats(stream, &len, 1);
2199
2200                Animation* anim = pMesh->createAnimation(name, len);
2201
2202                // tracks
2203                unsigned short streamID;
2204
2205                if (!stream->eof())
2206                {
2207                        streamID = readChunk(stream);
2208                        while(!stream->eof() &&
2209                                streamID == M_ANIMATION_TRACK)
2210                        {
2211                                switch(streamID)
2212                                {
2213                                case M_ANIMATION_TRACK:
2214                                        readAnimationTrack(stream, anim, pMesh);
2215                                        break;
2216                                };
2217                                if (!stream->eof())
2218                                {
2219                                        streamID = readChunk(stream);
2220                                }
2221
2222                        }
2223                        if (!stream->eof())
2224                        {
2225                                // Backpedal back to start of stream
2226                                stream->skip(-STREAM_OVERHEAD_SIZE);
2227                        }
2228                }
2229        }
2230        //---------------------------------------------------------------------
2231        void MeshSerializerImpl::readAnimationTrack(DataStreamPtr& stream,
2232                Animation* anim, Mesh* pMesh)
2233        {
2234                // ushort type
2235                uint16 inAnimType;
2236                readShorts(stream, &inAnimType, 1);
2237                VertexAnimationType animType = (VertexAnimationType)inAnimType;
2238
2239                // unsigned short target
2240                uint16 target;
2241                readShorts(stream, &target, 1);
2242
2243                VertexAnimationTrack* track = anim->createVertexTrack(target,
2244                        pMesh->getVertexDataByTrackHandle(target), animType);
2245
2246                // keyframes
2247                unsigned short streamID;
2248
2249                if (!stream->eof())
2250                {
2251                        streamID = readChunk(stream);
2252                        while(!stream->eof() &&
2253                                (streamID == M_ANIMATION_MORPH_KEYFRAME ||
2254                                 streamID == M_ANIMATION_POSE_KEYFRAME))
2255                        {
2256                                switch(streamID)
2257                                {
2258                                case M_ANIMATION_MORPH_KEYFRAME:
2259                                        readMorphKeyFrame(stream, track);
2260                                        break;
2261                                case M_ANIMATION_POSE_KEYFRAME:
2262                                        readPoseKeyFrame(stream, track);
2263                                        break;
2264                                };
2265                                if (!stream->eof())
2266                                {
2267                                        streamID = readChunk(stream);
2268                                }
2269
2270                        }
2271                        if (!stream->eof())
2272                        {
2273                                // Backpedal back to start of stream
2274                                stream->skip(-STREAM_OVERHEAD_SIZE);
2275                        }
2276                }
2277
2278        }
2279        //---------------------------------------------------------------------
2280        void MeshSerializerImpl::readMorphKeyFrame(DataStreamPtr& stream, VertexAnimationTrack* track)
2281        {
2282                // float time
2283                float timePos;
2284                readFloats(stream, &timePos, 1);
2285
2286                VertexMorphKeyFrame* kf = track->createVertexMorphKeyFrame(timePos);
2287
2288                // Create buffer, allow read and use shadow buffer
2289                size_t vertexCount = track->getAssociatedVertexData()->vertexCount;
2290                HardwareVertexBufferSharedPtr vbuf =
2291                        HardwareBufferManager::getSingleton().createVertexBuffer(
2292                                VertexElement::getTypeSize(VET_FLOAT3), vertexCount,
2293                                HardwareBuffer::HBU_STATIC, true);
2294                // float x,y,z                  // repeat by number of vertices in original geometry
2295                float* pDst = static_cast<float*>(
2296                        vbuf->lock(HardwareBuffer::HBL_DISCARD));
2297                readFloats(stream, pDst, vertexCount * 3);
2298                vbuf->unlock();
2299                kf->setVertexBuffer(vbuf);
2300
2301        }
2302        //---------------------------------------------------------------------
2303        void MeshSerializerImpl::readPoseKeyFrame(DataStreamPtr& stream, VertexAnimationTrack* track)
2304        {
2305                // float time
2306                float timePos;
2307                readFloats(stream, &timePos, 1);
2308
2309                // Create keyframe
2310                VertexPoseKeyFrame* kf = track->createVertexPoseKeyFrame(timePos);
2311
2312                unsigned short streamID;
2313
2314                if (!stream->eof())
2315                {
2316                        streamID = readChunk(stream);
2317                        while(!stream->eof() &&
2318                                streamID == M_ANIMATION_POSE_REF)
2319                        {
2320                                switch(streamID)
2321                                {
2322                                case M_ANIMATION_POSE_REF:
2323                                        uint16 poseIndex;
2324                                        float influence;
2325                                        // unsigned short poseIndex
2326                                        readShorts(stream, &poseIndex, 1);
2327                                        // float influence
2328                                        readFloats(stream, &influence, 1);
2329
2330                                        kf->addPoseReference(poseIndex, influence);
2331
2332                                        break;
2333                                };
2334                                if (!stream->eof())
2335                                {
2336                                        streamID = readChunk(stream);
2337                                }
2338
2339                        }
2340                        if (!stream->eof())
2341                        {
2342                                // Backpedal back to start of stream
2343                                stream->skip(-STREAM_OVERHEAD_SIZE);
2344                        }
2345                }
2346
2347        }
2348        //---------------------------------------------------------------------
2349    //---------------------------------------------------------------------
2350    //---------------------------------------------------------------------
2351    MeshSerializerImpl_v1_2::MeshSerializerImpl_v1_2()
2352    {
2353        // Version number
2354        mVersion = "[MeshSerializer_v1.20]";
2355    }
2356    //---------------------------------------------------------------------
2357    MeshSerializerImpl_v1_2::~MeshSerializerImpl_v1_2()
2358    {
2359    }
2360    //---------------------------------------------------------------------
2361    void MeshSerializerImpl_v1_2::readMesh(DataStreamPtr& stream, Mesh* pMesh)
2362    {
2363        MeshSerializerImpl::readMesh(stream, pMesh);
2364        // Always automatically build edge lists for this version
2365        pMesh->mAutoBuildEdgeLists = true;
2366
2367    }
2368    //---------------------------------------------------------------------
2369    void MeshSerializerImpl_v1_2::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
2370        VertexData* dest)
2371    {
2372        unsigned short texCoordSet = 0;
2373
2374        unsigned short bindIdx = 0;
2375
2376        dest->vertexStart = 0;
2377
2378        unsigned int vertexCount = 0;
2379        readInts(stream, &vertexCount, 1);
2380        dest->vertexCount = vertexCount;
2381
2382        // Vertex buffers
2383
2384        readGeometryPositions(bindIdx, stream, pMesh, dest);
2385        ++bindIdx;
2386
2387        // Find optional geometry streams
2388        if (!stream->eof())
2389        {
2390            unsigned short streamID = readChunk(stream);
2391            while(!stream->eof() &&
2392                (streamID == M_GEOMETRY_NORMALS ||
2393                 streamID == M_GEOMETRY_COLOURS ||
2394                 streamID == M_GEOMETRY_TEXCOORDS ))
2395            {
2396                switch (streamID)
2397                {
2398                case M_GEOMETRY_NORMALS:
2399                    readGeometryNormals(bindIdx++, stream, pMesh, dest);
2400                    break;
2401                case M_GEOMETRY_COLOURS:
2402                    readGeometryColours(bindIdx++, stream, pMesh, dest);
2403                    break;
2404                case M_GEOMETRY_TEXCOORDS:
2405                    readGeometryTexCoords(bindIdx++, stream, pMesh, dest, texCoordSet++);
2406                    break;
2407                }
2408                // Get next stream
2409                if (!stream->eof())
2410                {
2411                    streamID = readChunk(stream);
2412                }
2413            }
2414            if (!stream->eof())
2415            {
2416                // Backpedal back to start of non-submesh stream
2417                stream->skip(-STREAM_OVERHEAD_SIZE);
2418            }
2419        }
2420    }
2421    //---------------------------------------------------------------------
2422    void MeshSerializerImpl_v1_2::readGeometryPositions(unsigned short bindIdx,
2423        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
2424    {
2425        float *pFloat = 0;
2426        HardwareVertexBufferSharedPtr vbuf;
2427        // float* pVertices (x, y, z order x numVertices)
2428        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_POSITION);
2429        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
2430            dest->vertexDeclaration->getVertexSize(bindIdx),
2431            dest->vertexCount,
2432            pMesh->mVertexBufferUsage,
2433                        pMesh->mIndexBufferShadowBuffer);
2434        pFloat = static_cast<float*>(
2435            vbuf->lock(HardwareBuffer::HBL_DISCARD));
2436        readFloats(stream, pFloat, dest->vertexCount * 3);
2437        vbuf->unlock();
2438        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
2439    }
2440    //---------------------------------------------------------------------
2441    void MeshSerializerImpl_v1_2::readGeometryNormals(unsigned short bindIdx,
2442        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
2443    {
2444        float *pFloat = 0;
2445        HardwareVertexBufferSharedPtr vbuf;
2446        // float* pNormals (x, y, z order x numVertices)
2447        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_NORMAL);
2448        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
2449            dest->vertexDeclaration->getVertexSize(bindIdx),
2450            dest->vertexCount,
2451            pMesh->mVertexBufferUsage,
2452                        pMesh->mVertexBufferShadowBuffer);
2453        pFloat = static_cast<float*>(
2454            vbuf->lock(HardwareBuffer::HBL_DISCARD));
2455        readFloats(stream, pFloat, dest->vertexCount * 3);
2456        vbuf->unlock();
2457        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
2458    }
2459    //---------------------------------------------------------------------
2460    void MeshSerializerImpl_v1_2::readGeometryColours(unsigned short bindIdx,
2461        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
2462    {
2463        RGBA* pRGBA = 0;
2464        HardwareVertexBufferSharedPtr vbuf;
2465        // unsigned long* pColours (RGBA 8888 format x numVertices)
2466        dest->vertexDeclaration->addElement(bindIdx, 0, VET_COLOUR, VES_DIFFUSE);
2467        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
2468            dest->vertexDeclaration->getVertexSize(bindIdx),
2469            dest->vertexCount,
2470            pMesh->mVertexBufferUsage,
2471                        pMesh->mVertexBufferShadowBuffer);
2472        pRGBA = static_cast<RGBA*>(
2473            vbuf->lock(HardwareBuffer::HBL_DISCARD));
2474        readInts(stream, pRGBA, dest->vertexCount);
2475        vbuf->unlock();
2476        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
2477    }
2478    //---------------------------------------------------------------------
2479    void MeshSerializerImpl_v1_2::readGeometryTexCoords(unsigned short bindIdx,
2480        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
2481    {
2482        float *pFloat = 0;
2483        HardwareVertexBufferSharedPtr vbuf;
2484        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
2485        unsigned short dim;
2486        readShorts(stream, &dim, 1);
2487        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
2488        dest->vertexDeclaration->addElement(
2489            bindIdx,
2490            0,
2491            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
2492            VES_TEXTURE_COORDINATES,
2493            texCoordSet);
2494        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
2495            dest->vertexDeclaration->getVertexSize(bindIdx),
2496            dest->vertexCount,
2497            pMesh->mVertexBufferUsage,
2498                        pMesh->mVertexBufferShadowBuffer);
2499        pFloat = static_cast<float*>(
2500            vbuf->lock(HardwareBuffer::HBL_DISCARD));
2501        readFloats(stream, pFloat, dest->vertexCount * dim);
2502        vbuf->unlock();
2503        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
2504    }
2505    //---------------------------------------------------------------------
2506    //---------------------------------------------------------------------
2507    //---------------------------------------------------------------------
2508    MeshSerializerImpl_v1_1::MeshSerializerImpl_v1_1()
2509    {
2510        // Version number
2511        mVersion = "[MeshSerializer_v1.10]";
2512    }
2513    //---------------------------------------------------------------------
2514    MeshSerializerImpl_v1_1::~MeshSerializerImpl_v1_1()
2515    {
2516    }
2517    //---------------------------------------------------------------------
2518    void MeshSerializerImpl_v1_1::readGeometryTexCoords(unsigned short bindIdx,
2519        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
2520    {
2521        float *pFloat = 0;
2522        HardwareVertexBufferSharedPtr vbuf;
2523        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
2524        unsigned short dim;
2525        readShorts(stream, &dim, 1);
2526        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
2527        dest->vertexDeclaration->addElement(
2528            bindIdx,
2529            0,
2530            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
2531            VES_TEXTURE_COORDINATES,
2532            texCoordSet);
2533        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
2534            dest->vertexDeclaration->getVertexSize(bindIdx),
2535            dest->vertexCount,
2536            pMesh->getVertexBufferUsage(),
2537                        pMesh->isVertexBufferShadowed());
2538        pFloat = static_cast<float*>(
2539            vbuf->lock(HardwareBuffer::HBL_DISCARD));
2540        readFloats(stream, pFloat, dest->vertexCount * dim);
2541
2542        // Adjust individual v values to (1 - v)
2543        if (dim == 2)
2544        {
2545            for (size_t i = 0; i < dest->vertexCount; ++i)
2546            {
2547                ++pFloat; // skip u
2548                *pFloat = 1.0 - *pFloat; // v = 1 - v
2549                ++pFloat;
2550            }
2551
2552        }
2553        vbuf->unlock();
2554        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
2555    }
2556    //---------------------------------------------------------------------
2557    //---------------------------------------------------------------------
2558    //---------------------------------------------------------------------
2559
2560
2561
2562
2563}
2564
Note: See TracBrowser for help on using the repository browser.