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

Revision 657, 68.0 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26
27#include "OgreMeshSerializerImpl.h"
28#include "OgreMeshFileFormat.h"
29#include "OgreMesh.h"
30#include "OgreSubMesh.h"
31#include "OgreException.h"
32#include "OgreMaterialManager.h"
33#include "OgreLogManager.h"
34#include "OgreSkeleton.h"
35#include "OgreHardwareBufferManager.h"
36#include "OgreMaterial.h"
37#include "OgreTechnique.h"
38#include "OgrePass.h"
39
40#if OGRE_COMPILER == OGRE_COMPILER_MSVC
41// Disable conversion warnings, we do a lot of them, intentionally
42#   pragma warning (disable : 4267)
43#endif
44
45
46namespace Ogre {
47
48    /// stream overhead = ID + size
49    const long STREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32);
50    //---------------------------------------------------------------------
51    MeshSerializerImpl::MeshSerializerImpl()
52    {
53
54        // Version number
55        mVersion = "[MeshSerializer_v1.30]";
56    }
57    //---------------------------------------------------------------------
58    MeshSerializerImpl::~MeshSerializerImpl()
59    {
60    }
61    //---------------------------------------------------------------------
62    void MeshSerializerImpl::exportMesh(const Mesh* pMesh, const String& filename)
63    {
64        LogManager::getSingleton().logMessage("MeshSerializer writing mesh data to " + filename + "...");
65
66        // Check that the mesh has it's bounds set
67        if (pMesh->getBounds().isNull() || pMesh->getBoundingSphereRadius() == 0.0f)
68        {
69            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The Mesh you have supplied does not have its"
70                " bounds completely defined. Define them first before exporting.",
71                "MeshSerializerImpl::exportMesh");
72        }
73        mpfFile = fopen(filename.c_str(), "wb");
74
75        writeFileHeader();
76        LogManager::getSingleton().logMessage("File header written.");
77
78
79        LogManager::getSingleton().logMessage("Writing mesh data...");
80        writeMesh(pMesh);
81        LogManager::getSingleton().logMessage("Mesh data exported.");
82
83        fclose(mpfFile);
84        LogManager::getSingleton().logMessage("MeshSerializer export successful.");
85    }
86    //---------------------------------------------------------------------
87    void MeshSerializerImpl::importMesh(DataStreamPtr& stream, Mesh* pMesh)
88    {
89
90        // Check header
91        readFileHeader(stream);
92
93        unsigned short streamID;
94        while(!stream->eof())
95        {
96            streamID = readChunk(stream);
97            switch (streamID)
98            {
99            case M_MESH:
100                readMesh(stream, pMesh);
101                break;
102                        }
103
104        }
105    }
106    //---------------------------------------------------------------------
107    void MeshSerializerImpl::writeMesh(const Mesh* pMesh)
108    {
109        // Header
110        writeChunkHeader(M_MESH, calcMeshSize(pMesh));
111
112                // bool skeletallyAnimated
113                bool skelAnim = pMesh->hasSkeleton();
114                writeBools(&skelAnim, 1);
115
116        // Write shared geometry
117        if (pMesh->sharedVertexData)
118            writeGeometry(pMesh->sharedVertexData);
119
120        // Write Submeshes
121        for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
122        {
123            LogManager::getSingleton().logMessage("Writing submesh...");
124            writeSubMesh(pMesh->getSubMesh(i));
125            LogManager::getSingleton().logMessage("Submesh exported.");
126        }
127
128        // Write skeleton info if required
129        if (pMesh->hasSkeleton())
130        {
131            LogManager::getSingleton().logMessage("Exporting skeleton link...");
132            // Write skeleton link
133            writeSkeletonLink(pMesh->getSkeletonName());
134            LogManager::getSingleton().logMessage("Skeleton link exported.");
135
136            // Write bone assignments
137            if (!pMesh->mBoneAssignments.empty())
138            {
139                LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");
140
141                Mesh::VertexBoneAssignmentList::const_iterator vi;
142                for (vi = pMesh->mBoneAssignments.begin();
143                vi != pMesh->mBoneAssignments.end(); ++vi)
144                {
145                    writeMeshBoneAssignment(vi->second);
146                }
147
148                LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
149            }
150        }
151
152        // Write LOD data if any
153        if (pMesh->getNumLodLevels() > 1)
154        {
155            LogManager::getSingleton().logMessage("Exporting LOD information....");
156            writeLodInfo(pMesh);
157            LogManager::getSingleton().logMessage("LOD information exported.");
158           
159        }
160        // Write bounds information
161        LogManager::getSingleton().logMessage("Exporting bounds information....");
162        writeBoundsInfo(pMesh);
163        LogManager::getSingleton().logMessage("Bounds information exported.");
164
165                // Write submesh name table
166                LogManager::getSingleton().logMessage("Exporting submesh name table...");
167                writeSubMeshNameTable(pMesh);
168                LogManager::getSingleton().logMessage("Submesh name table exported.");
169               
170                // Write edge lists
171                if (pMesh->isEdgeListBuilt())
172                {
173                        LogManager::getSingleton().logMessage("Exporting edge lists...");
174                        writeEdgeList(pMesh);
175                        LogManager::getSingleton().logMessage("Edge lists exported");
176                }
177
178    }
179    //---------------------------------------------------------------------
180        // Added by DrEvil
181        void MeshSerializerImpl::writeSubMeshNameTable(const Mesh* pMesh)
182        {
183                // Header
184                writeChunkHeader(M_SUBMESH_NAME_TABLE, calcSubMeshNameTableSize(pMesh));
185
186                // Loop through and save out the index and names.
187                Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();
188
189                while(it != pMesh->mSubMeshNameMap.end())
190                {
191                        // Header
192                        writeChunkHeader(M_SUBMESH_NAME_TABLE_ELEMENT, STREAM_OVERHEAD_SIZE +
193                                sizeof(unsigned short) + (unsigned long)it->first.length() + 1);
194
195                        // write the index
196                        writeShorts(&it->second, 1);
197                        // name
198                writeString(it->first);
199
200                        ++it;
201                }
202        }
203    //---------------------------------------------------------------------
204    void MeshSerializerImpl::writeSubMesh(const SubMesh* s)
205    {
206        // Header
207        writeChunkHeader(M_SUBMESH, calcSubMeshSize(s));
208
209        // char* materialName
210        writeString(s->getMaterialName());
211
212        // bool useSharedVertices
213        writeBools(&s->useSharedVertices, 1);
214
215                unsigned int indexCount = s->indexData->indexCount;
216        writeInts(&indexCount, 1);
217
218        // bool indexes32Bit
219        bool idx32bit = (s->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
220        writeBools(&idx32bit, 1);
221
222        // unsigned short* faceVertexIndices ((indexCount)
223        HardwareIndexBufferSharedPtr ibuf = s->indexData->indexBuffer;
224        void* pIdx = ibuf->lock(HardwareBuffer::HBL_READ_ONLY);
225        if (idx32bit)
226        {
227            unsigned int* pIdx32 = static_cast<unsigned int*>(pIdx);
228            writeInts(pIdx32, s->indexData->indexCount);
229        }
230        else
231        {
232            unsigned short* pIdx16 = static_cast<unsigned short*>(pIdx);
233            writeShorts(pIdx16, s->indexData->indexCount);
234        }
235        ibuf->unlock();
236
237        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
238        if (!s->useSharedVertices)
239        {
240            writeGeometry(s->vertexData);
241        }
242       
243        // Operation type
244        writeSubMeshOperation(s);
245
246        // Bone assignments
247        if (!s->mBoneAssignments.empty())
248        {
249            LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");
250
251            SubMesh::VertexBoneAssignmentList::const_iterator vi;
252            for (vi = s->mBoneAssignments.begin();
253            vi != s->mBoneAssignments.end(); ++vi)
254            {
255                writeSubMeshBoneAssignment(vi->second);
256            }
257
258            LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
259        }
260
261
262    }
263    //---------------------------------------------------------------------
264    void MeshSerializerImpl::writeSubMeshOperation(const SubMesh* sm)
265    {
266        // Header
267        writeChunkHeader(M_SUBMESH_OPERATION, calcSubMeshOperationSize(sm));
268
269        // unsigned short operationType
270        unsigned short opType = static_cast<unsigned short>(sm->operationType);
271        writeShorts(&opType, 1);
272    }
273    //---------------------------------------------------------------------
274    void MeshSerializerImpl::writeGeometry(const VertexData* vertexData)
275    {
276                // calc size
277        const VertexDeclaration::VertexElementList& elemList =
278            vertexData->vertexDeclaration->getElements();
279        const VertexBufferBinding::VertexBufferBindingMap& bindings =
280            vertexData->vertexBufferBinding->getBindings();
281        VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbiend;
282
283                size_t size = STREAM_OVERHEAD_SIZE + sizeof(unsigned int) + // base
284                        (STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5)); // elements
285        vbiend = bindings.end();
286                for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
287                {
288                        const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
289                        size += (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
290                }
291
292                // Header
293        writeChunkHeader(M_GEOMETRY, size);
294
295        unsigned int vertexCount = vertexData->vertexCount;
296        writeInts(&vertexCount, 1);
297
298                // Vertex declaration
299                size = STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5);
300                writeChunkHeader(M_GEOMETRY_VERTEX_DECLARATION, size);
301               
302        VertexDeclaration::VertexElementList::const_iterator vei, veiend;
303                veiend = elemList.end();
304                unsigned short tmp;
305                size = STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5;
306                for (vei = elemList.begin(); vei != veiend; ++vei)
307                {
308                        const VertexElement& elem = *vei;
309                        writeChunkHeader(M_GEOMETRY_VERTEX_ELEMENT, size);
310                        // unsigned short source;       // buffer bind source
311                        tmp = elem.getSource();
312                        writeShorts(&tmp, 1);
313                        // unsigned short type;         // VertexElementType
314                        tmp = static_cast<unsigned short>(elem.getType());
315                        writeShorts(&tmp, 1);
316                        // unsigned short semantic; // VertexElementSemantic
317                        tmp = static_cast<unsigned short>(elem.getSemantic());
318                        writeShorts(&tmp, 1);
319                        // unsigned short offset;       // start offset in buffer in bytes
320                        tmp = static_cast<unsigned short>(elem.getOffset());
321                        writeShorts(&tmp, 1);
322                        // unsigned short index;        // index of the semantic (for colours and texture coords)
323                        tmp = elem.getIndex();
324                        writeShorts(&tmp, 1);
325
326                }
327
328                // Buffers and bindings
329                vbiend = bindings.end();
330                for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
331                {
332                        const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
333                        size = (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
334                        writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER,  size);
335                        // unsigned short bindIndex;    // Index to bind this buffer to
336                        tmp = vbi->first;
337                        writeShorts(&tmp, 1);
338                        // unsigned short vertexSize;   // Per-vertex size, must agree with declaration at this index
339                        tmp = (unsigned short)vbuf->getVertexSize();
340                        writeShorts(&tmp, 1);
341                       
342                        // Data
343                        size = STREAM_OVERHEAD_SIZE + vbuf->getSizeInBytes();
344                        writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size);
345                        void* pBuf = vbuf->lock(HardwareBuffer::HBL_READ_ONLY);
346#               if OGRE_ENDIAN == OGRE_ENDIAN_BIG
347                        // endian conversion for OSX
348                        // Copy data
349                        unsigned char* tempData = new unsigned char[vbuf->getSizeInBytes()];
350                        memcpy(tempData, pBuf, vbuf->getSizeInBytes());
351                        flipToLittleEndian(
352                                tempData,
353                                vertexData->vertexCount,
354                                vbuf->getVertexSize(),
355                                vertexData->vertexDeclaration->findElementsBySource(vbi->first));
356                        writeData(tempData, vbuf->getVertexSize(), vertexData->vertexCount);
357                        delete [] tempData;
358#               else
359                        writeData(pBuf, vbuf->getVertexSize(), vertexData->vertexCount);
360#               endif
361            vbuf->unlock();
362                }
363
364
365    }
366    //---------------------------------------------------------------------
367        size_t MeshSerializerImpl::calcSubMeshNameTableSize(const Mesh* pMesh)
368        {
369                size_t size = STREAM_OVERHEAD_SIZE;
370                // Figure out the size of the Name table.
371                // Iterate through the subMeshList & add up the size of the indexes and names.
372                Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();               
373                while(it != pMesh->mSubMeshNameMap.end())
374                {
375                        // size of the index
376                        size += sizeof(uint16);
377                        // name
378                        size += it->first.length() + 1;
379
380                        ++it;
381                }                       
382
383                // size of the sub-mesh name table.
384                return size;
385        }
386    //---------------------------------------------------------------------
387    size_t MeshSerializerImpl::calcMeshSize(const Mesh* pMesh)
388    {
389        size_t size = STREAM_OVERHEAD_SIZE;
390
391        // Num shared vertices
392        size += sizeof(uint32);
393
394        // Geometry
395        if (pMesh->sharedVertexData && pMesh->sharedVertexData->vertexCount > 0)
396        {
397            size += calcGeometrySize(pMesh->sharedVertexData);
398        }
399
400        // Submeshes
401        for (unsigned short i = 0; i < pMesh->getNumSubMeshes(); ++i)
402        {
403            size += calcSubMeshSize(pMesh->getSubMesh(i));
404        }
405
406        // Skeleton link
407        if (pMesh->hasSkeleton())
408        {
409            size += calcSkeletonLinkSize(pMesh->getSkeletonName());
410        }
411
412                // Submesh name table
413                size += calcSubMeshNameTableSize(pMesh);
414
415                // Edge list
416                if (pMesh->isEdgeListBuilt())
417                {
418                        size += calcEdgeListSize(pMesh);
419                }
420               
421                return size;
422    }
423    //---------------------------------------------------------------------
424    size_t MeshSerializerImpl::calcSubMeshSize(const SubMesh* pSub)
425    {
426        size_t size = STREAM_OVERHEAD_SIZE;
427
428        // Material name
429        size += pSub->getMaterialName().length() + 1;
430
431        // bool useSharedVertices
432        size += sizeof(bool);
433        // unsigned int indexCount
434        size += sizeof(unsigned int);
435        // bool indexes32bit
436        size += sizeof(bool);
437        // unsigned int* faceVertexIndices
438        size += sizeof(unsigned int) * pSub->indexData->indexCount;
439
440        // Geometry
441        if (!pSub->useSharedVertices)
442        {
443            size += calcGeometrySize(pSub->vertexData);
444        }
445
446        return size;
447    }
448    //---------------------------------------------------------------------
449    size_t MeshSerializerImpl::calcSubMeshOperationSize(const SubMesh* pSub)
450    {
451        return STREAM_OVERHEAD_SIZE + sizeof(uint16);
452    }
453    //---------------------------------------------------------------------
454    size_t MeshSerializerImpl::calcGeometrySize(const VertexData* vertexData)
455    {
456        size_t size = STREAM_OVERHEAD_SIZE;
457
458        // Num vertices
459        size += sizeof(unsigned int);
460
461        const VertexDeclaration::VertexElementList& elems =
462            vertexData->vertexDeclaration->getElements();
463
464        VertexDeclaration::VertexElementList::const_iterator i, iend;
465        iend = elems.end();
466        for (i = elems.begin(); i != iend; ++i)
467        {
468            const VertexElement& elem = *i;
469            // Vertex element
470            size += VertexElement::getTypeSize(elem.getType()) * vertexData->vertexCount;
471        }
472        return size;
473    }
474    //---------------------------------------------------------------------
475    void MeshSerializerImpl::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
476        VertexData* dest)
477    {
478
479        dest->vertexStart = 0;
480
481        unsigned int vertexCount = 0;
482        readInts(stream, &vertexCount, 1);
483        dest->vertexCount = vertexCount;
484
485        // Find optional geometry streams
486        if (!stream->eof())
487        {
488            unsigned short streamID = readChunk(stream);
489            while(!stream->eof() &&
490                (streamID == M_GEOMETRY_VERTEX_DECLARATION ||
491                 streamID == M_GEOMETRY_VERTEX_BUFFER ))
492            {
493                switch (streamID)
494                {
495                case M_GEOMETRY_VERTEX_DECLARATION:
496                    readGeometryVertexDeclaration(stream, pMesh, dest);
497                    break;
498                case M_GEOMETRY_VERTEX_BUFFER:
499                    readGeometryVertexBuffer(stream, pMesh, dest);
500                    break;
501                }
502                // Get next stream
503                if (!stream->eof())
504                {
505                    streamID = readChunk(stream);
506                }
507            }
508            if (!stream->eof())
509            {
510                // Backpedal back to start of non-submesh stream
511                stream->skip(-STREAM_OVERHEAD_SIZE);
512            }
513        }
514    }
515    //---------------------------------------------------------------------
516    void MeshSerializerImpl::readGeometryVertexDeclaration(DataStreamPtr& stream,
517        Mesh* pMesh, VertexData* dest)
518    {
519        // Find optional geometry streams
520        if (!stream->eof())
521        {
522            unsigned short streamID = readChunk(stream);
523            while(!stream->eof() &&
524                (streamID == M_GEOMETRY_VERTEX_ELEMENT ))
525            {
526                switch (streamID)
527                {
528                case M_GEOMETRY_VERTEX_ELEMENT:
529                    readGeometryVertexElement(stream, pMesh, dest);
530                    break;
531                }
532                // Get next stream
533                if (!stream->eof())
534                {
535                    streamID = readChunk(stream);
536                }
537            }
538            if (!stream->eof())
539            {
540                // Backpedal back to start of non-submesh stream
541                stream->skip(-STREAM_OVERHEAD_SIZE);
542            }
543        }
544               
545        }
546    //---------------------------------------------------------------------
547    void MeshSerializerImpl::readGeometryVertexElement(DataStreamPtr& stream,
548        Mesh* pMesh, VertexData* dest)
549    {
550                unsigned short source, offset, index, tmp;
551                VertexElementType vType;
552                VertexElementSemantic vSemantic;
553                // unsigned short source;       // buffer bind source
554                readShorts(stream, &source, 1);
555                // unsigned short type;         // VertexElementType
556                readShorts(stream, &tmp, 1);
557                vType = static_cast<VertexElementType>(tmp);
558                // unsigned short semantic; // VertexElementSemantic
559                readShorts(stream, &tmp, 1);
560                vSemantic = static_cast<VertexElementSemantic>(tmp);
561                // unsigned short offset;       // start offset in buffer in bytes
562                readShorts(stream, &offset, 1);
563                // unsigned short index;        // index of the semantic
564                readShorts(stream, &index, 1);
565
566                dest->vertexDeclaration->addElement(source, offset, vType, vSemantic, index);
567
568        }
569    //---------------------------------------------------------------------
570    void MeshSerializerImpl::readGeometryVertexBuffer(DataStreamPtr& stream,
571        Mesh* pMesh, VertexData* dest)
572    {
573                unsigned short bindIndex, vertexSize;
574                // unsigned short bindIndex;    // Index to bind this buffer to
575                readShorts(stream, &bindIndex, 1);
576                // unsigned short vertexSize;   // Per-vertex size, must agree with declaration at this index
577                readShorts(stream, &vertexSize, 1);
578
579                // Check for vertex data header
580                unsigned short headerID;
581                headerID = readChunk(stream);
582                if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA)
583                {
584                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Can't find vertex buffer data area",
585                "MeshSerializerImpl::readGeometryVertexBuffer");
586                }
587                // Check that vertex size agrees
588                if (dest->vertexDeclaration->getVertexSize(bindIndex) != vertexSize)
589                {
590                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer vertex size does not agree with vertex declaration",
591                "MeshSerializerImpl::readGeometryVertexBuffer");
592                }
593               
594                // Create / populate vertex buffer
595                HardwareVertexBufferSharedPtr vbuf;
596        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
597            vertexSize,
598            dest->vertexCount,
599            pMesh->mVertexBufferUsage,
600                        pMesh->mVertexBufferShadowBuffer);
601        void* pBuf = vbuf->lock(HardwareBuffer::HBL_DISCARD);
602        stream->read(pBuf, dest->vertexCount * vertexSize);
603
604                // endian conversion for OSX
605                flipFromLittleEndian(
606                        pBuf,
607                        dest->vertexCount,
608                        vertexSize,
609                        dest->vertexDeclaration->findElementsBySource(bindIndex));
610        vbuf->unlock();
611               
612                // Set binding
613        dest->vertexBufferBinding->setBinding(bindIndex, vbuf);
614
615        }
616    //---------------------------------------------------------------------
617        void MeshSerializerImpl::readSubMeshNameTable(DataStreamPtr& stream, Mesh* pMesh)
618        {
619                // The map for
620                std::map<unsigned short, String> subMeshNames;
621                unsigned short streamID, subMeshIndex;
622
623                // Need something to store the index, and the objects name
624                // This table is a method that imported meshes can retain their naming
625                // so that the names established in the modelling software can be used
626                // to get the sub-meshes by name. The exporter must support exporting
627                // the optional stream M_SUBMESH_NAME_TABLE.
628
629        // Read in all the sub-streams. Each sub-stream should contain an index and Ogre::String for the name.
630                if (!stream->eof())
631                {
632                        streamID = readChunk(stream);
633                        while(!stream->eof() && (streamID == M_SUBMESH_NAME_TABLE_ELEMENT ))
634                        {
635                                // Read in the index of the submesh.
636                                readShorts(stream, &subMeshIndex, 1);
637                                // Read in the String and map it to its index.
638                                subMeshNames[subMeshIndex] = readString(stream);                                       
639
640                                // If we're not end of file get the next stream ID
641                                if (!stream->eof())
642                                        streamID = readChunk(stream);
643                        }
644                        if (!stream->eof())
645                        {
646                                // Backpedal back to start of stream
647                                stream->skip(-STREAM_OVERHEAD_SIZE);
648                        }
649                }
650
651                // Set all the submeshes names
652                // ?
653
654                // Loop through and save out the index and names.
655                std::map<unsigned short, String>::const_iterator it = subMeshNames.begin();
656
657                while(it != subMeshNames.end())
658                {                       
659                        // Name this submesh to the stored name.
660                        pMesh->nameSubMesh(it->second, it->first);
661                        ++it;
662                }
663
664
665
666        }
667    //---------------------------------------------------------------------
668    void MeshSerializerImpl::readMesh(DataStreamPtr& stream, Mesh* pMesh)
669    {
670        unsigned short streamID;
671
672        // Never automatically build edge lists for this version
673        // expect them in the file or not at all
674        pMesh->mAutoBuildEdgeLists = false;
675
676                // bool skeletallyAnimated
677                readBools(stream, &mIsSkeletallyAnimated, 1);
678
679        // Find all substreams
680        if (!stream->eof())
681        {
682            streamID = readChunk(stream);
683            while(!stream->eof() &&
684                (streamID == M_GEOMETRY ||
685                                 streamID == M_SUBMESH ||
686                 streamID == M_MESH_SKELETON_LINK ||
687                 streamID == M_MESH_BONE_ASSIGNMENT ||
688                                 streamID == M_MESH_LOD ||
689                 streamID == M_MESH_BOUNDS ||
690                                 streamID == M_SUBMESH_NAME_TABLE ||
691                                 streamID == M_EDGE_LISTS))
692            {
693                switch(streamID)
694                {
695                                case M_GEOMETRY:
696                                        pMesh->sharedVertexData = new VertexData();
697                                        try {
698                                                readGeometry(stream, pMesh, pMesh->sharedVertexData);
699                                        }
700                                        catch (Exception& e)
701                                        {
702                                                if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
703                                                {
704                                                        // duff geometry data entry with 0 vertices
705                                                        delete pMesh->sharedVertexData;
706                                                        pMesh->sharedVertexData = 0;
707                                                        // Skip this stream (pointer will have been returned to just after header)
708                                                        stream->skip(mCurrentstreamLen - STREAM_OVERHEAD_SIZE);
709                                                }
710                                                else
711                                                {
712                                                        throw;
713                                                }
714                                        }
715                                        break;
716                case M_SUBMESH:
717                    readSubMesh(stream, pMesh);
718                    break;
719                case M_MESH_SKELETON_LINK:
720                    readSkeletonLink(stream, pMesh);
721                    break;
722                case M_MESH_BONE_ASSIGNMENT:
723                    readMeshBoneAssignment(stream, pMesh);
724                    break;
725                case M_MESH_LOD:
726                                        readMeshLodInfo(stream, pMesh);
727                                        break;
728                case M_MESH_BOUNDS:
729                    readBoundsInfo(stream, pMesh);
730                    break;
731                                case M_SUBMESH_NAME_TABLE:
732                    readSubMeshNameTable(stream, pMesh);
733                                        break;
734                case M_EDGE_LISTS:
735                    readEdgeList(stream, pMesh);
736                    break;
737                                       
738                }
739
740                if (!stream->eof())
741                {
742                    streamID = readChunk(stream);
743                }
744
745            }
746            if (!stream->eof())
747            {
748                // Backpedal back to start of stream
749                stream->skip(-STREAM_OVERHEAD_SIZE);
750            }
751        }
752
753    }
754    //---------------------------------------------------------------------
755    void MeshSerializerImpl::readSubMesh(DataStreamPtr& stream, Mesh* pMesh)
756    {
757        unsigned short streamID;
758
759        SubMesh* sm = pMesh->createSubMesh();
760        // char* materialName
761        String materialName = readString(stream);
762        sm->setMaterialName(materialName);
763
764        // bool useSharedVertices
765        readBools(stream,&sm->useSharedVertices, 1);
766
767        sm->indexData->indexStart = 0;
768        unsigned int indexCount = 0;
769        readInts(stream, &indexCount, 1);
770        sm->indexData->indexCount = indexCount;
771
772        HardwareIndexBufferSharedPtr ibuf;
773        // bool indexes32Bit
774        bool idx32bit;
775        readBools(stream, &idx32bit, 1);
776        if (idx32bit)
777        {
778            ibuf = HardwareBufferManager::getSingleton().
779                createIndexBuffer(
780                    HardwareIndexBuffer::IT_32BIT,
781                    sm->indexData->indexCount,
782                    pMesh->mIndexBufferUsage,
783                                        pMesh->mIndexBufferShadowBuffer);
784            // unsigned int* faceVertexIndices
785            unsigned int* pIdx = static_cast<unsigned int*>(
786                ibuf->lock(HardwareBuffer::HBL_DISCARD)
787                );
788            readInts(stream, pIdx, sm->indexData->indexCount);
789            ibuf->unlock();
790
791        }
792        else // 16-bit
793        {
794            ibuf = HardwareBufferManager::getSingleton().
795                createIndexBuffer(
796                    HardwareIndexBuffer::IT_16BIT,
797                    sm->indexData->indexCount,
798                    pMesh->mIndexBufferUsage,
799                                        pMesh->mIndexBufferShadowBuffer);
800            // unsigned short* faceVertexIndices
801            unsigned short* pIdx = static_cast<unsigned short*>(
802                ibuf->lock(HardwareBuffer::HBL_DISCARD)
803                );
804            readShorts(stream, pIdx, sm->indexData->indexCount);
805            ibuf->unlock();
806        }
807        sm->indexData->indexBuffer = ibuf;
808
809        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
810        if (!sm->useSharedVertices)
811        {
812            streamID = readChunk(stream);
813            if (streamID != M_GEOMETRY)
814            {
815                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file",
816                    "MeshSerializerImpl::readSubMesh");
817            }
818            sm->vertexData = new VertexData();
819            readGeometry(stream, pMesh, sm->vertexData);
820        }
821
822
823        // Find all bone assignments (if present)
824        if (!stream->eof())
825        {
826            streamID = readChunk(stream);
827            while(!stream->eof() &&
828                (streamID == M_SUBMESH_BONE_ASSIGNMENT ||
829                 streamID == M_SUBMESH_OPERATION))
830            {
831                switch(streamID)
832                {
833                case M_SUBMESH_OPERATION:
834                    readSubMeshOperation(stream, pMesh, sm);
835                    break;
836                case M_SUBMESH_BONE_ASSIGNMENT:
837                    readSubMeshBoneAssignment(stream, pMesh, sm);
838                    break;
839                }
840
841                if (!stream->eof())
842                {
843                    streamID = readChunk(stream);
844                }
845
846            }
847            if (!stream->eof())
848            {
849                // Backpedal back to start of stream
850                stream->skip(-STREAM_OVERHEAD_SIZE);
851            }
852        }
853       
854
855    }
856    //---------------------------------------------------------------------
857    void MeshSerializerImpl::readSubMeshOperation(DataStreamPtr& stream,
858        Mesh* pMesh, SubMesh* sm)
859    {
860        // unsigned short operationType
861        unsigned short opType;
862        readShorts(stream, &opType, 1);
863        sm->operationType = static_cast<RenderOperation::OperationType>(opType);
864    }
865    //---------------------------------------------------------------------
866    void MeshSerializerImpl::writeSkeletonLink(const String& skelName)
867    {
868        writeChunkHeader(M_MESH_SKELETON_LINK, calcSkeletonLinkSize(skelName));
869
870        writeString(skelName);
871
872    }
873    //---------------------------------------------------------------------
874    void MeshSerializerImpl::readSkeletonLink(DataStreamPtr& stream, Mesh* pMesh)
875    {
876        String skelName = readString(stream);
877        pMesh->setSkeletonName(skelName);
878    }
879    //---------------------------------------------------------------------
880    void MeshSerializerImpl::readTextureLayer(DataStreamPtr& stream, Mesh* pMesh,
881        MaterialPtr& pMat)
882    {
883        // Material definition section phased out of 1.1
884    }
885    //---------------------------------------------------------------------
886    size_t MeshSerializerImpl::calcSkeletonLinkSize(const String& skelName)
887    {
888        size_t size = STREAM_OVERHEAD_SIZE;
889
890        size += skelName.length() + 1;
891
892        return size;
893
894    }
895    //---------------------------------------------------------------------
896    void MeshSerializerImpl::writeMeshBoneAssignment(const VertexBoneAssignment& assign)
897    {
898        writeChunkHeader(M_MESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
899
900        // unsigned int vertexIndex;
901        writeInts(&(assign.vertexIndex), 1);
902        // unsigned short boneIndex;
903        writeShorts(&(assign.boneIndex), 1);
904        // float weight;
905        writeFloats(&(assign.weight), 1);
906    }
907    //---------------------------------------------------------------------
908    void MeshSerializerImpl::writeSubMeshBoneAssignment(const VertexBoneAssignment& assign)
909    {
910        writeChunkHeader(M_SUBMESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
911
912        // unsigned int vertexIndex;
913        writeInts(&(assign.vertexIndex), 1);
914        // unsigned short boneIndex;
915        writeShorts(&(assign.boneIndex), 1);
916        // float weight;
917        writeFloats(&(assign.weight), 1);
918    }
919    //---------------------------------------------------------------------
920    void MeshSerializerImpl::readMeshBoneAssignment(DataStreamPtr& stream, Mesh* pMesh)
921    {
922        VertexBoneAssignment assign;
923
924        // unsigned int vertexIndex;
925        readInts(stream, &(assign.vertexIndex),1);
926        // unsigned short boneIndex;
927        readShorts(stream, &(assign.boneIndex),1);
928        // float weight;
929        readFloats(stream, &(assign.weight), 1);
930
931        pMesh->addBoneAssignment(assign);
932
933    }
934    //---------------------------------------------------------------------
935    void MeshSerializerImpl::readSubMeshBoneAssignment(DataStreamPtr& stream,
936        Mesh* pMesh, SubMesh* sub)
937    {
938        VertexBoneAssignment assign;
939
940        // unsigned int vertexIndex;
941        readInts(stream, &(assign.vertexIndex),1);
942        // unsigned short boneIndex;
943        readShorts(stream, &(assign.boneIndex),1);
944        // float weight;
945        readFloats(stream, &(assign.weight), 1);
946
947        sub->addBoneAssignment(assign);
948
949    }
950    //---------------------------------------------------------------------
951    size_t MeshSerializerImpl::calcBoneAssignmentSize(void)
952    {
953        size_t size = STREAM_OVERHEAD_SIZE;
954
955        // Vert index
956        size += sizeof(unsigned int);
957        // Bone index
958        size += sizeof(unsigned short);
959        // weight
960        size += sizeof(float);
961
962        return size;
963    }
964    //---------------------------------------------------------------------
965    void MeshSerializerImpl::writeLodInfo(const Mesh* pMesh)
966    {
967        unsigned short numLods = pMesh->getNumLodLevels();
968        bool manual = pMesh->isLodManual();
969        writeLodSummary(numLods, manual);
970
971                // Loop from LOD 1 (not 0, this is full detail)
972        for (unsigned short i = 1; i < numLods; ++i)
973        {
974                        const MeshLodUsage& usage = pMesh->getLodLevel(i);
975                        if (manual)
976                        {
977                                writeLodUsageManual(usage);
978                        }
979                        else
980                        {
981                                writeLodUsageGenerated(pMesh, usage, i);
982                        }
983           
984        }
985       
986
987    }
988    //---------------------------------------------------------------------
989    void MeshSerializerImpl::writeLodSummary(unsigned short numLevels, bool manual)
990    {
991        // Header
992        size_t size = STREAM_OVERHEAD_SIZE;
993        // unsigned short numLevels;
994        size += sizeof(unsigned short);
995        // bool manual;  (true for manual alternate meshes, false for generated)
996        size += sizeof(bool);
997        writeChunkHeader(M_MESH_LOD, size);
998
999        // Details
1000        // unsigned short numLevels;
1001        writeShorts(&numLevels, 1);
1002        // bool manual;  (true for manual alternate meshes, false for generated)
1003        writeBools(&manual, 1);
1004
1005       
1006    }
1007    //---------------------------------------------------------------------
1008    void MeshSerializerImpl::writeLodUsageManual(const MeshLodUsage& usage)
1009    {
1010        // Header
1011        size_t size = STREAM_OVERHEAD_SIZE;
1012        size_t manualSize = STREAM_OVERHEAD_SIZE;
1013        // float fromDepthSquared;
1014        size += sizeof(float);
1015        // Manual part size
1016
1017        // String manualMeshName;
1018        manualSize += usage.manualName.length() + 1;
1019
1020        size += manualSize;
1021
1022        writeChunkHeader(M_MESH_LOD_USAGE, size);
1023        writeFloats(&(usage.fromDepthSquared), 1);
1024
1025        writeChunkHeader(M_MESH_LOD_MANUAL, manualSize);
1026        writeString(usage.manualName);
1027       
1028
1029    }
1030    //---------------------------------------------------------------------
1031    void MeshSerializerImpl::writeLodUsageGenerated(const Mesh* pMesh, const MeshLodUsage& usage,
1032                unsigned short lodNum)
1033    {
1034                // Usage Header
1035        size_t size = STREAM_OVERHEAD_SIZE;
1036                unsigned short subidx;
1037
1038        // float fromDepthSquared;
1039        size += sizeof(float);
1040
1041        // Calc generated SubMesh sections size
1042                for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
1043                {
1044                        // header
1045                        size += STREAM_OVERHEAD_SIZE;
1046                        // unsigned int numFaces;
1047                        size += sizeof(unsigned int);
1048                        SubMesh* sm = pMesh->getSubMesh(subidx);
1049            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1050
1051            // bool indexes32Bit
1052                        size += sizeof(bool);
1053                        // unsigned short*/int* faceIndexes; 
1054            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
1055            {
1056                            size += static_cast<unsigned long>(
1057                    sizeof(unsigned int) * indexData->indexCount);
1058            }
1059            else
1060            {
1061                            size += static_cast<unsigned long>(
1062                    sizeof(unsigned short) * indexData->indexCount);
1063            }
1064
1065                }
1066
1067        writeChunkHeader(M_MESH_LOD_USAGE, size);
1068        writeFloats(&(usage.fromDepthSquared), 1);
1069
1070                // Now write sections
1071        // Calc generated SubMesh sections size
1072                for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
1073                {
1074                        size = STREAM_OVERHEAD_SIZE;
1075                        // unsigned int numFaces;
1076                        size += sizeof(unsigned int);
1077                        SubMesh* sm = pMesh->getSubMesh(subidx);
1078            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1079            // bool indexes32Bit
1080                        size += sizeof(bool);
1081                        // unsigned short*/int* faceIndexes; 
1082            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
1083            {
1084                            size += static_cast<unsigned long>(
1085                    sizeof(unsigned int) * indexData->indexCount);
1086            }
1087            else
1088            {
1089                            size += static_cast<unsigned long>(
1090                    sizeof(unsigned short) * indexData->indexCount);
1091            }
1092
1093                        writeChunkHeader(M_MESH_LOD_GENERATED, size);
1094                        unsigned int idxCount = static_cast<unsigned int>(indexData->indexCount);
1095                        writeInts(&idxCount, 1);
1096            // Lock index buffer to write
1097            HardwareIndexBufferSharedPtr ibuf = indexData->indexBuffer;
1098                        // bool indexes32bit
1099                        bool idx32 = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
1100                        writeBools(&idx32, 1);
1101            if (idx32)
1102            {
1103                unsigned int* pIdx = static_cast<unsigned int*>(
1104                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
1105                            writeInts(pIdx, indexData->indexCount);
1106                ibuf->unlock();
1107            }
1108            else
1109            {
1110                unsigned short* pIdx = static_cast<unsigned short*>(
1111                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
1112                            writeShorts(pIdx, indexData->indexCount);
1113                ibuf->unlock();
1114            }
1115                }
1116       
1117
1118    }
1119    //---------------------------------------------------------------------
1120    void MeshSerializerImpl::writeBoundsInfo(const Mesh* pMesh)
1121    {
1122                // Usage Header
1123        unsigned long size = STREAM_OVERHEAD_SIZE;
1124
1125        size += sizeof(float) * 7;
1126        writeChunkHeader(M_MESH_BOUNDS, size);
1127
1128        // float minx, miny, minz
1129        const Vector3& min = pMesh->mAABB.getMinimum();
1130        const Vector3& max = pMesh->mAABB.getMaximum();
1131        writeFloats(&min.x, 1);
1132        writeFloats(&min.y, 1);
1133        writeFloats(&min.z, 1);
1134        // float maxx, maxy, maxz
1135        writeFloats(&max.x, 1);
1136        writeFloats(&max.y, 1);
1137        writeFloats(&max.z, 1);
1138        // float radius
1139        writeFloats(&pMesh->mBoundRadius, 1);
1140
1141    }
1142    //---------------------------------------------------------------------
1143    void MeshSerializerImpl::readBoundsInfo(DataStreamPtr& stream, Mesh* pMesh)
1144    {
1145        Vector3 min, max;
1146        // float minx, miny, minz
1147        readFloats(stream, &min.x, 1);
1148        readFloats(stream, &min.y, 1);
1149        readFloats(stream, &min.z, 1);
1150        // float maxx, maxy, maxz
1151        readFloats(stream, &max.x, 1);
1152        readFloats(stream, &max.y, 1);
1153        readFloats(stream, &max.z, 1);
1154        AxisAlignedBox box(min, max);
1155        pMesh->_setBounds(box, true);
1156        // float radius
1157        float radius;
1158        readFloats(stream, &radius, 1);
1159        pMesh->_setBoundingSphereRadius(radius);
1160
1161
1162
1163    }
1164    //---------------------------------------------------------------------
1165        void MeshSerializerImpl::readMeshLodInfo(DataStreamPtr& stream, Mesh* pMesh)
1166        {
1167                unsigned short streamID, i;
1168
1169        // unsigned short numLevels;
1170                readShorts(stream, &(pMesh->mNumLods), 1);
1171        // bool manual;  (true for manual alternate meshes, false for generated)
1172                readBools(stream, &(pMesh->mIsLodManual), 1);
1173
1174                // Preallocate submesh lod face data if not manual
1175                if (!pMesh->mIsLodManual)
1176                {
1177                        unsigned short numsubs = pMesh->getNumSubMeshes();
1178                        for (i = 0; i < numsubs; ++i)
1179                        {
1180                                SubMesh* sm = pMesh->getSubMesh(i);
1181                                sm->mLodFaceList.resize(pMesh->mNumLods-1);
1182                        }
1183                }
1184
1185                // Loop from 1 rather than 0 (full detail index is not in file)
1186                for (i = 1; i < pMesh->mNumLods; ++i)
1187                {
1188                        streamID = readChunk(stream);
1189                        if (streamID != M_MESH_LOD_USAGE)
1190                        {
1191                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1192                                        "Missing M_MESH_LOD_USAGE stream in " + pMesh->getName(),
1193                                        "MeshSerializerImpl::readMeshLodInfo");
1194                        }
1195                        // Read depth
1196                        MeshLodUsage usage;
1197                        readFloats(stream, &(usage.fromDepthSquared), 1);
1198
1199                        if (pMesh->isLodManual())
1200                        {
1201                                readMeshLodUsageManual(stream, pMesh, i, usage);
1202                        }
1203                        else //(!pMesh->isLodManual)
1204                        {
1205                                readMeshLodUsageGenerated(stream, pMesh, i, usage);
1206                        }
1207            usage.edgeData = NULL;
1208
1209                        // Save usage
1210                        pMesh->mMeshLodUsageList.push_back(usage);
1211                }
1212
1213
1214        }
1215    //---------------------------------------------------------------------
1216        void MeshSerializerImpl::readMeshLodUsageManual(DataStreamPtr& stream,
1217        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
1218        {
1219                unsigned long streamID;
1220                // Read detail stream
1221                streamID = readChunk(stream);
1222                if (streamID != M_MESH_LOD_MANUAL)
1223                {
1224                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1225                                "Missing M_MESH_LOD_MANUAL stream in " + pMesh->getName(),
1226                                "MeshSerializerImpl::readMeshLodUsageManual");
1227                }
1228
1229                usage.manualName = readString(stream);
1230                usage.manualMesh.setNull(); // will trigger load later
1231        }
1232    //---------------------------------------------------------------------
1233        void MeshSerializerImpl::readMeshLodUsageGenerated(DataStreamPtr& stream,
1234        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
1235        {
1236                usage.manualName = "";
1237                usage.manualMesh.setNull();
1238
1239                // Get one set of detail per SubMesh
1240                unsigned short numSubs, i;
1241                unsigned long streamID;
1242                numSubs = pMesh->getNumSubMeshes();
1243                for (i = 0; i < numSubs; ++i)
1244                {
1245                        streamID = readChunk(stream);
1246                        if (streamID != M_MESH_LOD_GENERATED)
1247                        {
1248                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1249                                        "Missing M_MESH_LOD_GENERATED stream in " + pMesh->getName(),
1250                                        "MeshSerializerImpl::readMeshLodUsageGenerated");
1251                        }
1252
1253                        SubMesh* sm = pMesh->getSubMesh(i);
1254                        // lodNum - 1 because SubMesh doesn't store full detail LOD
1255            sm->mLodFaceList[lodNum - 1] = new IndexData();
1256                        IndexData* indexData = sm->mLodFaceList[lodNum - 1];
1257            // unsigned int numIndexes
1258            unsigned int numIndexes;
1259                        readInts(stream, &numIndexes, 1);
1260            indexData->indexCount = static_cast<size_t>(numIndexes);
1261            // bool indexes32Bit
1262            bool idx32Bit;
1263            readBools(stream, &idx32Bit, 1);
1264            // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
1265            if (idx32Bit)
1266            {
1267                indexData->indexBuffer = HardwareBufferManager::getSingleton().
1268                    createIndexBuffer(HardwareIndexBuffer::IT_32BIT, indexData->indexCount,
1269                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
1270                unsigned int* pIdx = static_cast<unsigned int*>(
1271                    indexData->indexBuffer->lock(
1272                        0,
1273                        indexData->indexBuffer->getSizeInBytes(),
1274                        HardwareBuffer::HBL_DISCARD) );
1275
1276                            readInts(stream, pIdx, indexData->indexCount);
1277                indexData->indexBuffer->unlock();
1278
1279            }
1280            else
1281            {
1282                indexData->indexBuffer = HardwareBufferManager::getSingleton().
1283                    createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
1284                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
1285                unsigned short* pIdx = static_cast<unsigned short*>(
1286                    indexData->indexBuffer->lock(
1287                        0,
1288                        indexData->indexBuffer->getSizeInBytes(),
1289                        HardwareBuffer::HBL_DISCARD) );
1290                            readShorts(stream, pIdx, indexData->indexCount);
1291                indexData->indexBuffer->unlock();
1292
1293            }
1294
1295                }
1296        }
1297    //---------------------------------------------------------------------
1298    void MeshSerializerImpl::flipFromLittleEndian(void* pData, size_t vertexCount,
1299        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1300        {
1301#       if OGRE_ENDIAN == OGRE_ENDIAN_BIG
1302        flipEndian(pData, vertexCount, vertexSize, elems);
1303#       endif   
1304    }
1305    //---------------------------------------------------------------------
1306    void MeshSerializerImpl::flipToLittleEndian(void* pData, size_t vertexCount,
1307                        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1308        {
1309#       if OGRE_ENDIAN == OGRE_ENDIAN_BIG
1310        flipEndian(pData, vertexCount, vertexSize, elems);
1311#       endif   
1312        }
1313    //---------------------------------------------------------------------
1314    void MeshSerializerImpl::flipEndian(void* pData, size_t vertexCount,
1315        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
1316        {
1317                void *pBase = pData;
1318                for (size_t v = 0; v < vertexCount; ++v)
1319                {
1320                        VertexDeclaration::VertexElementList::const_iterator ei, eiend;
1321                        eiend = elems.end();
1322                        for (ei = elems.begin(); ei != eiend; ++ei)
1323                        {
1324                                void *pElem;
1325                                // re-base pointer to the element
1326                                (*ei).baseVertexPointerToElement(pBase, &pElem);
1327                                // Flip the endian based on the type
1328                                size_t typeSize = 0;
1329                                switch (VertexElement::getBaseType((*ei).getType()))
1330                                {
1331                                        case VET_FLOAT1:
1332                                                typeSize = sizeof(float);
1333                                                break;
1334                                        case VET_SHORT1:
1335                                                typeSize = sizeof(short);
1336                                                break;
1337                                        case VET_COLOUR:
1338                                                typeSize = sizeof(RGBA);
1339                                                break;
1340                                        case VET_UBYTE4:
1341                                                typeSize = 0; // NO FLIPPING
1342                                                break;
1343                                };
1344                Serializer::flipEndian(pElem, typeSize,
1345                                        VertexElement::getTypeCount((*ei).getType()));
1346                               
1347                        }
1348
1349                        pBase = static_cast<void*>(
1350                                static_cast<unsigned char*>(pBase) + vertexSize);
1351                       
1352                }
1353        }
1354    //---------------------------------------------------------------------
1355        size_t MeshSerializerImpl::calcEdgeListSize(const Mesh* pMesh)
1356        {
1357        size_t size = STREAM_OVERHEAD_SIZE;
1358
1359        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
1360        {
1361           
1362            const EdgeData* edgeData = pMesh->getEdgeList(i);
1363            bool isManual = pMesh->isLodManual() && (i > 0);
1364
1365            size += calcEdgeListLodSize(edgeData, isManual);
1366
1367        }
1368
1369        return size;
1370        }
1371    //---------------------------------------------------------------------
1372    size_t MeshSerializerImpl::calcEdgeListLodSize(const EdgeData* edgeData, bool isManual)
1373    {
1374        size_t size = STREAM_OVERHEAD_SIZE;
1375
1376        // unsigned short lodIndex
1377        size += sizeof(uint16);
1378
1379        // bool isManual                        // If manual, no edge data here, loaded from manual mesh
1380        size += sizeof(bool);
1381        if (!isManual)
1382        {
1383            // unsigned long numTriangles
1384            size += sizeof(uint32);
1385            // unsigned long numEdgeGroups
1386            size += sizeof(uint32);
1387            // Triangle* triangleList
1388            size_t triSize = 0;
1389            // unsigned long indexSet
1390            // unsigned long vertexSet
1391            // unsigned long vertIndex[3]
1392            // unsigned long sharedVertIndex[3]
1393            // float normal[4]
1394            triSize += sizeof(uint32) * 8
1395                    + sizeof(float) * 4;
1396
1397            size += triSize * edgeData->triangles.size();
1398            // Write the groups
1399            for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
1400                gi != edgeData->edgeGroups.end(); ++gi)
1401            {
1402                const EdgeData::EdgeGroup& edgeGroup = *gi;
1403                size += calcEdgeGroupSize(edgeGroup);
1404            }
1405
1406        }
1407
1408        return size;
1409    }
1410    //---------------------------------------------------------------------
1411    size_t MeshSerializerImpl::calcEdgeGroupSize(const EdgeData::EdgeGroup& group)
1412    {
1413        size_t size = STREAM_OVERHEAD_SIZE;
1414
1415        // unsigned long vertexSet
1416        size += sizeof(uint32);
1417        // unsigned long numEdges
1418        size += sizeof(uint32);
1419        // Edge* edgeList
1420        size_t edgeSize = 0;
1421        // unsigned long  triIndex[2]
1422        // unsigned long  vertIndex[2]
1423        // unsigned long  sharedVertIndex[2]
1424        // bool degenerate
1425        edgeSize += sizeof(uint32) * 6 + sizeof(bool);
1426        size += edgeSize * group.edges.size();
1427
1428        return size;
1429    }
1430    //---------------------------------------------------------------------
1431        void MeshSerializerImpl::writeEdgeList(const Mesh* pMesh)
1432        {
1433        writeChunkHeader(M_EDGE_LISTS, calcEdgeListSize(pMesh));
1434
1435        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
1436        {
1437            const EdgeData* edgeData = pMesh->getEdgeList(i);
1438            bool isManual = pMesh->isLodManual() && (i > 0);
1439            writeChunkHeader(M_EDGE_LIST_LOD, calcEdgeListLodSize(edgeData, isManual));
1440
1441            // unsigned short lodIndex
1442            writeShorts(&i, 1);
1443
1444            // bool isManual                    // If manual, no edge data here, loaded from manual mesh
1445            writeBools(&isManual, 1);
1446            if (!isManual)
1447            {
1448                // unsigned long  numTriangles
1449                uint32 count = static_cast<uint32>(edgeData->triangles.size());
1450                writeInts(&count, 1);
1451                // unsigned long numEdgeGroups
1452                count = static_cast<uint32>(edgeData->edgeGroups.size());
1453                writeInts(&count, 1);
1454                // Triangle* triangleList
1455                // Iterate rather than writing en-masse to allow endian conversion
1456                for (EdgeData::TriangleList::const_iterator t = edgeData->triangles.begin();
1457                    t != edgeData->triangles.end(); ++t)
1458                {
1459                    const EdgeData::Triangle& tri = *t;
1460                    // unsigned long indexSet;
1461                    uint32 tmp[3];
1462                    tmp[0] = tri.indexSet;
1463                    writeInts(tmp, 1);
1464                    // unsigned long vertexSet;
1465                    tmp[0] = tri.vertexSet;
1466                    writeInts(tmp, 1);
1467                    // unsigned long vertIndex[3];
1468                    tmp[0] = tri.vertIndex[0];
1469                    tmp[1] = tri.vertIndex[1];
1470                    tmp[2] = tri.vertIndex[2];
1471                    writeInts(tmp, 3);
1472                    // unsigned long sharedVertIndex[3];
1473                    tmp[0] = tri.sharedVertIndex[0];
1474                    tmp[1] = tri.sharedVertIndex[1];
1475                    tmp[2] = tri.sharedVertIndex[2];
1476                    writeInts(tmp, 3);
1477                    // float normal[4];   
1478                    writeFloats(&(tri.normal.x), 4);
1479
1480                }
1481                // Write the groups
1482                for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
1483                    gi != edgeData->edgeGroups.end(); ++gi)
1484                {
1485                    const EdgeData::EdgeGroup& edgeGroup = *gi;
1486                    writeChunkHeader(M_EDGE_GROUP, calcEdgeGroupSize(edgeGroup));
1487                    // unsigned long vertexSet
1488                    uint32 vertexSet = static_cast<uint32>(edgeGroup.vertexSet);
1489                    writeInts(&vertexSet, 1);
1490                    // unsigned long numEdges
1491                    count = static_cast<uint32>(edgeGroup.edges.size());
1492                    writeInts(&count, 1);
1493                    // Edge* edgeList
1494                    // Iterate rather than writing en-masse to allow endian conversion
1495                    for (EdgeData::EdgeList::const_iterator ei = edgeGroup.edges.begin();
1496                        ei != edgeGroup.edges.end(); ++ei)
1497                    {
1498                        const EdgeData::Edge& edge = *ei;
1499                        uint32 tmp[2];
1500                        // unsigned long  triIndex[2]
1501                        tmp[0] = edge.triIndex[0];
1502                        tmp[1] = edge.triIndex[1];
1503                        writeInts(tmp, 2);
1504                        // unsigned long  vertIndex[2]
1505                        tmp[0] = edge.vertIndex[0];
1506                        tmp[1] = edge.vertIndex[1];
1507                        writeInts(tmp, 2);
1508                        // unsigned long  sharedVertIndex[2]
1509                        tmp[0] = edge.sharedVertIndex[0];
1510                        tmp[1] = edge.sharedVertIndex[1];
1511                        writeInts(tmp, 2);
1512                        // bool degenerate
1513                        writeBools(&(edge.degenerate), 1);
1514                    }
1515
1516                }
1517
1518            }
1519
1520        }
1521        }
1522    //---------------------------------------------------------------------
1523        void MeshSerializerImpl::readEdgeList(DataStreamPtr& stream, Mesh* pMesh)
1524        {
1525        unsigned short streamID;
1526
1527        if (!stream->eof())
1528        {
1529            streamID = readChunk(stream);
1530            while(!stream->eof() &&
1531                streamID == M_EDGE_LIST_LOD)
1532            {
1533                // Process single LOD
1534
1535                // unsigned short lodIndex
1536                unsigned short lodIndex;
1537                readShorts(stream, &lodIndex, 1);
1538
1539                // bool isManual                        // If manual, no edge data here, loaded from manual mesh
1540                bool isManual;
1541                readBools(stream, &isManual, 1);
1542                // Only load in non-manual levels; others will be connected up by Mesh on demand
1543                if (!isManual)
1544                {
1545                    MeshLodUsage& usage = const_cast<MeshLodUsage&>(pMesh->getLodLevel(lodIndex));
1546
1547                    usage.edgeData = new EdgeData();
1548                    // unsigned long numTriangles
1549                    uint32 numTriangles;
1550                    readInts(stream, &numTriangles, 1);
1551                    // Allocate correct amount of memory
1552                    usage.edgeData->triangles.resize(numTriangles);
1553                    // unsigned long numEdgeGroups
1554                    uint32 numEdgeGroups;
1555                    readInts(stream, &numEdgeGroups, 1);
1556                    // Allocate correct amount of memory
1557                    usage.edgeData->edgeGroups.resize(numEdgeGroups);
1558                    // Triangle* triangleList
1559                    uint32 tmp[3];
1560                    for (size_t t = 0; t < numTriangles; ++t)
1561                    {
1562                        EdgeData::Triangle& tri = usage.edgeData->triangles[t];
1563                        // unsigned long indexSet
1564                        readInts(stream, tmp, 1);
1565                        tri.indexSet = tmp[0];
1566                        // unsigned long vertexSet
1567                        readInts(stream, tmp, 1);
1568                        tri.vertexSet = tmp[0];
1569                        // unsigned long vertIndex[3]
1570                        readInts(stream, tmp, 3);
1571                        tri.vertIndex[0] = tmp[0];
1572                        tri.vertIndex[1] = tmp[1];
1573                        tri.vertIndex[2] = tmp[2];
1574                        // unsigned long sharedVertIndex[3]
1575                        readInts(stream, tmp, 3);
1576                        tri.sharedVertIndex[0] = tmp[0];
1577                        tri.sharedVertIndex[1] = tmp[1];
1578                        tri.sharedVertIndex[2] = tmp[2];
1579                        // float normal[4]
1580                        readFloats(stream, &(tri.normal.x), 4);
1581
1582                    }
1583
1584                    for (uint32 eg = 0; eg < numEdgeGroups; ++eg)
1585                    {
1586                        streamID = readChunk(stream);
1587                        if (streamID != M_EDGE_GROUP)
1588                        {
1589                            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1590                                "Missing M_EDGE_GROUP stream",
1591                                "MeshSerializerImpl::readEdgeList");
1592                        }
1593                        EdgeData::EdgeGroup& edgeGroup = usage.edgeData->edgeGroups[eg];
1594
1595                        // unsigned long vertexSet
1596                        readInts(stream, tmp, 1);
1597                        edgeGroup.vertexSet = tmp[0];
1598                        // unsigned long numEdges
1599                        uint32 numEdges;
1600                        readInts(stream, &numEdges, 1);
1601                        edgeGroup.edges.resize(numEdges);
1602                        // Edge* edgeList
1603                        for (uint32 e = 0; e < numEdges; ++e)
1604                        {
1605                            EdgeData::Edge& edge = edgeGroup.edges[e];
1606                            // unsigned long  triIndex[2]
1607                            readInts(stream, tmp, 2);
1608                            edge.triIndex[0] = tmp[0];
1609                            edge.triIndex[1] = tmp[1];
1610                            // unsigned long  vertIndex[2]
1611                            readInts(stream, tmp, 2);
1612                            edge.vertIndex[0] = tmp[0];
1613                            edge.vertIndex[1] = tmp[1];
1614                            // unsigned long  sharedVertIndex[2]
1615                            readInts(stream, tmp, 2);
1616                            edge.sharedVertIndex[0] = tmp[0];
1617                            edge.sharedVertIndex[1] = tmp[1];
1618                            // bool degenerate
1619                            readBools(stream, &(edge.degenerate), 1);
1620                        }
1621                        // Populate edgeGroup.vertexData pointers
1622                        // If there is shared vertex data, vertexSet 0 is that,
1623                        // otherwise 0 is first dedicated
1624                        if (pMesh->sharedVertexData)
1625                        {
1626                            if (edgeGroup.vertexSet == 0)
1627                            {
1628                                edgeGroup.vertexData = pMesh->sharedVertexData;
1629                            }
1630                            else
1631                            {
1632                                edgeGroup.vertexData = pMesh->getSubMesh(
1633                                    edgeGroup.vertexSet-1)->vertexData;
1634                            }
1635                        }
1636                        else
1637                        {
1638                            edgeGroup.vertexData = pMesh->getSubMesh(
1639                                edgeGroup.vertexSet)->vertexData;
1640                        }
1641                    }
1642                   
1643                }
1644
1645                if (!stream->eof())
1646                {
1647                    streamID = readChunk(stream);
1648                }
1649
1650            }
1651            if (!stream->eof())
1652            {
1653                // Backpedal back to start of stream
1654                stream->skip(-STREAM_OVERHEAD_SIZE);
1655            }
1656        }
1657
1658
1659
1660        pMesh->mEdgeListsBuilt = true;
1661        }
1662    //---------------------------------------------------------------------
1663    //---------------------------------------------------------------------
1664    //---------------------------------------------------------------------
1665    MeshSerializerImpl_v1_2::MeshSerializerImpl_v1_2()
1666    {
1667        // Version number
1668        mVersion = "[MeshSerializer_v1.20]";
1669    }
1670    //---------------------------------------------------------------------
1671    MeshSerializerImpl_v1_2::~MeshSerializerImpl_v1_2()
1672    {
1673    }
1674    //---------------------------------------------------------------------
1675    void MeshSerializerImpl_v1_2::readMesh(DataStreamPtr& stream, Mesh* pMesh)
1676    {
1677        MeshSerializerImpl::readMesh(stream, pMesh);
1678        // Always automatically build edge lists for this version
1679        pMesh->mAutoBuildEdgeLists = true;
1680       
1681    }
1682    //---------------------------------------------------------------------
1683    void MeshSerializerImpl_v1_2::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
1684        VertexData* dest)
1685    {
1686        unsigned short texCoordSet = 0;
1687       
1688        unsigned short bindIdx = 0;
1689
1690        dest->vertexStart = 0;
1691
1692        unsigned int vertexCount = 0;
1693        readInts(stream, &vertexCount, 1);
1694        dest->vertexCount = vertexCount;
1695
1696        // Vertex buffers
1697
1698        readGeometryPositions(bindIdx, stream, pMesh, dest);
1699        ++bindIdx;
1700
1701        // Find optional geometry streams
1702        if (!stream->eof())
1703        {
1704            unsigned short streamID = readChunk(stream);
1705            while(!stream->eof() &&
1706                (streamID == M_GEOMETRY_NORMALS ||
1707                 streamID == M_GEOMETRY_COLOURS ||
1708                 streamID == M_GEOMETRY_TEXCOORDS ))
1709            {
1710                switch (streamID)
1711                {
1712                case M_GEOMETRY_NORMALS:
1713                    readGeometryNormals(bindIdx++, stream, pMesh, dest);
1714                    break;
1715                case M_GEOMETRY_COLOURS:
1716                    readGeometryColours(bindIdx++, stream, pMesh, dest);
1717                    break;
1718                case M_GEOMETRY_TEXCOORDS:
1719                    readGeometryTexCoords(bindIdx++, stream, pMesh, dest, texCoordSet++);
1720                    break;
1721                }
1722                // Get next stream
1723                if (!stream->eof())
1724                {
1725                    streamID = readChunk(stream);
1726                }
1727            }
1728            if (!stream->eof())
1729            {
1730                // Backpedal back to start of non-submesh stream
1731                stream->skip(-STREAM_OVERHEAD_SIZE);
1732            }
1733        }
1734    }
1735    //---------------------------------------------------------------------
1736    void MeshSerializerImpl_v1_2::readGeometryPositions(unsigned short bindIdx,
1737        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
1738    {
1739        float *pFloat = 0;
1740        HardwareVertexBufferSharedPtr vbuf;
1741        // float* pVertices (x, y, z order x numVertices)
1742        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_POSITION);
1743        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
1744            dest->vertexDeclaration->getVertexSize(bindIdx),
1745            dest->vertexCount,
1746            pMesh->mVertexBufferUsage,
1747                        pMesh->mIndexBufferShadowBuffer);
1748        pFloat = static_cast<float*>(
1749            vbuf->lock(HardwareBuffer::HBL_DISCARD));
1750        readFloats(stream, pFloat, dest->vertexCount * 3);
1751        vbuf->unlock();
1752        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
1753    }
1754    //---------------------------------------------------------------------
1755    void MeshSerializerImpl_v1_2::readGeometryNormals(unsigned short bindIdx,
1756        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
1757    {
1758        float *pFloat = 0;
1759        HardwareVertexBufferSharedPtr vbuf;
1760        // float* pNormals (x, y, z order x numVertices)
1761        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_NORMAL);
1762        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
1763            dest->vertexDeclaration->getVertexSize(bindIdx),
1764            dest->vertexCount,
1765            pMesh->mVertexBufferUsage,
1766                        pMesh->mVertexBufferShadowBuffer);
1767        pFloat = static_cast<float*>(
1768            vbuf->lock(HardwareBuffer::HBL_DISCARD));
1769        readFloats(stream, pFloat, dest->vertexCount * 3);
1770        vbuf->unlock();
1771        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
1772    }
1773    //---------------------------------------------------------------------
1774    void MeshSerializerImpl_v1_2::readGeometryColours(unsigned short bindIdx,
1775        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
1776    {
1777        RGBA* pRGBA = 0;
1778        HardwareVertexBufferSharedPtr vbuf;
1779        // unsigned long* pColours (RGBA 8888 format x numVertices)
1780        dest->vertexDeclaration->addElement(bindIdx, 0, VET_COLOUR, VES_DIFFUSE);
1781        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
1782            dest->vertexDeclaration->getVertexSize(bindIdx),
1783            dest->vertexCount,
1784            pMesh->mVertexBufferUsage,
1785                        pMesh->mVertexBufferShadowBuffer);
1786        pRGBA = static_cast<RGBA*>(
1787            vbuf->lock(HardwareBuffer::HBL_DISCARD));
1788        readInts(stream, pRGBA, dest->vertexCount);
1789        vbuf->unlock();
1790        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
1791    }
1792    //---------------------------------------------------------------------
1793    void MeshSerializerImpl_v1_2::readGeometryTexCoords(unsigned short bindIdx,
1794        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
1795    {
1796        float *pFloat = 0;
1797        HardwareVertexBufferSharedPtr vbuf;
1798        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
1799        unsigned short dim;
1800        readShorts(stream, &dim, 1);
1801        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
1802        dest->vertexDeclaration->addElement(
1803            bindIdx,
1804            0,
1805            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
1806            VES_TEXTURE_COORDINATES,
1807            texCoordSet);
1808        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
1809            dest->vertexDeclaration->getVertexSize(bindIdx),
1810            dest->vertexCount,
1811            pMesh->mVertexBufferUsage,
1812                        pMesh->mVertexBufferShadowBuffer);
1813        pFloat = static_cast<float*>(
1814            vbuf->lock(HardwareBuffer::HBL_DISCARD));
1815        readFloats(stream, pFloat, dest->vertexCount * dim);
1816        vbuf->unlock();
1817        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
1818    }
1819    //---------------------------------------------------------------------
1820    //---------------------------------------------------------------------
1821    //---------------------------------------------------------------------
1822    MeshSerializerImpl_v1_1::MeshSerializerImpl_v1_1()
1823    {
1824        // Version number
1825        mVersion = "[MeshSerializer_v1.10]";
1826    }
1827    //---------------------------------------------------------------------
1828    MeshSerializerImpl_v1_1::~MeshSerializerImpl_v1_1()
1829    {
1830    }
1831    //---------------------------------------------------------------------
1832    void MeshSerializerImpl_v1_1::readGeometryTexCoords(unsigned short bindIdx,
1833        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
1834    {
1835        float *pFloat = 0;
1836        HardwareVertexBufferSharedPtr vbuf;
1837        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
1838        unsigned short dim;
1839        readShorts(stream, &dim, 1);
1840        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
1841        dest->vertexDeclaration->addElement(
1842            bindIdx,
1843            0,
1844            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
1845            VES_TEXTURE_COORDINATES,
1846            texCoordSet);
1847        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
1848            dest->vertexDeclaration->getVertexSize(bindIdx),
1849            dest->vertexCount,
1850            pMesh->getVertexBufferUsage(),
1851                        pMesh->isVertexBufferShadowed());
1852        pFloat = static_cast<float*>(
1853            vbuf->lock(HardwareBuffer::HBL_DISCARD));
1854        readFloats(stream, pFloat, dest->vertexCount * dim);
1855
1856        // Adjust individual v values to (1 - v)
1857        if (dim == 2)
1858        {
1859            for (size_t i = 0; i < dest->vertexCount; ++i)
1860            {
1861                ++pFloat; // skip u
1862                *pFloat = 1.0 - *pFloat; // v = 1 - v
1863                ++pFloat;
1864            }
1865           
1866        }
1867        vbuf->unlock();
1868        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
1869    }
1870    //---------------------------------------------------------------------
1871    //---------------------------------------------------------------------
1872    //---------------------------------------------------------------------
1873
1874
1875
1876
1877}
1878
Note: See TracBrowser for help on using the repository browser.