Logo Search packages:      
Sourcecode: ogre version File versions

OgreMeshSerializerImpl.cpp

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#include "OgreMeshSerializerImpl.h"
#include "OgreMeshFileFormat.h"
#include "OgreMesh.h"
#include "OgreSubMesh.h"
#include "OgreException.h"
#include "OgreLogManager.h"
#include "OgreSkeleton.h"
#include "OgreHardwareBufferManager.h"
#include "OgreMaterial.h"
#include "OgreTechnique.h"
#include "OgrePass.h"
#include "OgreAnimation.h"
#include "OgreAnimationTrack.h"
#include "OgreKeyFrame.h"
#include "OgreRoot.h"

#if OGRE_COMPILER == OGRE_COMPILER_MSVC
// Disable conversion warnings, we do a lot of them, intentionally
#   pragma warning (disable : 4267)
#endif


namespace Ogre {

    /// stream overhead = ID + size
00056     const long STREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32);
    //---------------------------------------------------------------------
    MeshSerializerImpl::MeshSerializerImpl()
    {

        // Version number
        mVersion = "[MeshSerializer_v1.40]";
    }
    //---------------------------------------------------------------------
    MeshSerializerImpl::~MeshSerializerImpl()
    {
    }
    //---------------------------------------------------------------------
00069     void MeshSerializerImpl::exportMesh(const Mesh* pMesh, 
            const String& filename, Endian endianMode)
    {
        LogManager::getSingleton().logMessage("MeshSerializer writing mesh data to " + filename + "...");

            // Decide on endian mode
            determineEndianness(endianMode);

        // Check that the mesh has it's bounds set
        if (pMesh->getBounds().isNull() || pMesh->getBoundingSphereRadius() == 0.0f)
        {
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "The Mesh you have supplied does not have its"
                " bounds completely defined. Define them first before exporting.",
                "MeshSerializerImpl::exportMesh");
        }
        mpfFile = fopen(filename.c_str(), "wb");
            if (!mpfFile)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Unable to open file " + filename + " for writing",
                        "MeshSerializerImpl::exportMesh");
            }

        writeFileHeader();
        LogManager::getSingleton().logMessage("File header written.");


        LogManager::getSingleton().logMessage("Writing mesh data...");
        writeMesh(pMesh);
        LogManager::getSingleton().logMessage("Mesh data exported.");

        fclose(mpfFile);
        LogManager::getSingleton().logMessage("MeshSerializer export successful.");
    }
    //---------------------------------------------------------------------
00104     void MeshSerializerImpl::importMesh(DataStreamPtr& stream, Mesh* pMesh)
    {
            // Determine endianness (must be the first thing we do!)
            determineEndianness(stream);

        // Check header
        readFileHeader(stream);

        unsigned short streamID;
        while(!stream->eof())
        {
            streamID = readChunk(stream);
            switch (streamID)
            {
            case M_MESH:
                readMesh(stream, pMesh);
                break;
                  }

        }
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeMesh(const Mesh* pMesh)
    {
        // Header
        writeChunkHeader(M_MESH, calcMeshSize(pMesh));

            // bool skeletallyAnimated
            bool skelAnim = pMesh->hasSkeleton();
            writeBools(&skelAnim, 1);

        // Write shared geometry
        if (pMesh->sharedVertexData)
            writeGeometry(pMesh->sharedVertexData);

        // Write Submeshes
        for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
        {
            LogManager::getSingleton().logMessage("Writing submesh...");
            writeSubMesh(pMesh->getSubMesh(i));
            LogManager::getSingleton().logMessage("Submesh exported.");
        }

        // Write skeleton info if required
        if (pMesh->hasSkeleton())
        {
            LogManager::getSingleton().logMessage("Exporting skeleton link...");
            // Write skeleton link
            writeSkeletonLink(pMesh->getSkeletonName());
            LogManager::getSingleton().logMessage("Skeleton link exported.");

            // Write bone assignments
            if (!pMesh->mBoneAssignments.empty())
            {
                LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");

                Mesh::VertexBoneAssignmentList::const_iterator vi;
                for (vi = pMesh->mBoneAssignments.begin();
                vi != pMesh->mBoneAssignments.end(); ++vi)
                {
                    writeMeshBoneAssignment(vi->second);
                }

                LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
            }
        }

        // Write LOD data if any
        if (pMesh->getNumLodLevels() > 1)
        {
            LogManager::getSingleton().logMessage("Exporting LOD information....");
            writeLodInfo(pMesh);
            LogManager::getSingleton().logMessage("LOD information exported.");

        }
        // Write bounds information
        LogManager::getSingleton().logMessage("Exporting bounds information....");
        writeBoundsInfo(pMesh);
        LogManager::getSingleton().logMessage("Bounds information exported.");

            // Write submesh name table
            LogManager::getSingleton().logMessage("Exporting submesh name table...");
            writeSubMeshNameTable(pMesh);
            LogManager::getSingleton().logMessage("Submesh name table exported.");

            // Write edge lists
            if (pMesh->isEdgeListBuilt())
            {
                  LogManager::getSingleton().logMessage("Exporting edge lists...");
                  writeEdgeList(pMesh);
                  LogManager::getSingleton().logMessage("Edge lists exported");
            }

            // Write morph animation
            writePoses(pMesh);
            if (pMesh->hasVertexAnimation())
            {
                  writeAnimations(pMesh);
        }

        // Write submesh extremes
        writeExtremes(pMesh);
    }
    //---------------------------------------------------------------------
      // Added by DrEvil
      void MeshSerializerImpl::writeSubMeshNameTable(const Mesh* pMesh)
      {
            // Header
            writeChunkHeader(M_SUBMESH_NAME_TABLE, calcSubMeshNameTableSize(pMesh));

            // Loop through and save out the index and names.
            Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();

            while(it != pMesh->mSubMeshNameMap.end())
            {
                  // Header
                  writeChunkHeader(M_SUBMESH_NAME_TABLE_ELEMENT, STREAM_OVERHEAD_SIZE +
                        sizeof(unsigned short) + (unsigned long)it->first.length() + 1);

                  // write the index
                  writeShorts(&it->second, 1);
                  // name
              writeString(it->first);

                  ++it;
            }
      }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSubMesh(const SubMesh* s)
    {
        // Header
        writeChunkHeader(M_SUBMESH, calcSubMeshSize(s));

        // char* materialName
        writeString(s->getMaterialName());

        // bool useSharedVertices
        writeBools(&s->useSharedVertices, 1);

            unsigned int indexCount = s->indexData->indexCount;
        writeInts(&indexCount, 1);

        // bool indexes32Bit
        bool idx32bit = (s->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
        writeBools(&idx32bit, 1);

        // unsigned short* faceVertexIndices ((indexCount)
        HardwareIndexBufferSharedPtr ibuf = s->indexData->indexBuffer;
        void* pIdx = ibuf->lock(HardwareBuffer::HBL_READ_ONLY);
        if (idx32bit)
        {
            unsigned int* pIdx32 = static_cast<unsigned int*>(pIdx);
            writeInts(pIdx32, s->indexData->indexCount);
        }
        else
        {
            unsigned short* pIdx16 = static_cast<unsigned short*>(pIdx);
            writeShorts(pIdx16, s->indexData->indexCount);
        }
        ibuf->unlock();

        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
        if (!s->useSharedVertices)
        {
            writeGeometry(s->vertexData);
        }

        // end of sub mesh chunk

        // write out texture alias chunks
        writeSubMeshTextureAliases(s);

        // Operation type
        writeSubMeshOperation(s);

        // Bone assignments
        if (!s->mBoneAssignments.empty())
        {
            LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");

            SubMesh::VertexBoneAssignmentList::const_iterator vi;
            for (vi = s->mBoneAssignments.begin();
            vi != s->mBoneAssignments.end(); ++vi)
            {
                writeSubMeshBoneAssignment(vi->second);
            }

            LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
        }


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeExtremes(const Mesh *pMesh)
    {
        bool has_extremes = false;
        for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
        {
            SubMesh *sm = pMesh->getSubMesh(i);
            if (sm->extremityPoints.empty())
                continue;
            if (!has_extremes)
            {
                has_extremes = true;
                LogManager::getSingleton().logMessage("Writing submesh extremes...");
            }
            writeSubMeshExtremes(i, sm);
        }
        if (has_extremes)
            LogManager::getSingleton().logMessage("Extremes exported.");
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSubMeshExtremes(unsigned short idx, const SubMesh* s)
    {
        size_t chunkSize = STREAM_OVERHEAD_SIZE + sizeof (unsigned short) +
            s->extremityPoints.size () * sizeof (float) * 3;
        writeChunkHeader(M_TABLE_EXTREMES, chunkSize);

        writeShorts(&idx, 1);

        float *vertices = new float [s->extremityPoints.size() * 3];
            float *pVert = vertices;

        for (std::vector<Vector3>::const_iterator i = s->extremityPoints.begin();
             i != s->extremityPoints.end(); ++i)
        {
                  *pVert++ = i->x;
                  *pVert++ = i->y;
                  *pVert++ = i->z;
        }

        writeFloats(vertices, s->extremityPoints.size () * 3);
        delete [] vertices;
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSubMeshTextureAliases(const SubMesh* s)
    {
        size_t chunkSize;
        AliasTextureNamePairList::const_iterator i;

            LogManager::getSingleton().logMessage("Exporting submesh texture aliases...");

        // iterate through texture aliases and write them out as a chunk
        for (i = s->mTextureAliases.begin(); i != s->mTextureAliases.end(); ++i)
        {
            // calculate chunk size based on string length + 1.  Add 1 for the line feed.
            chunkSize = STREAM_OVERHEAD_SIZE + i->first.length() + i->second.length() + 2;
                  writeChunkHeader(M_SUBMESH_TEXTURE_ALIAS, chunkSize);
            // write out alias name
            writeString(i->first);
            // write out texture name
            writeString(i->second);
        }

            LogManager::getSingleton().logMessage("Submesh texture aliases exported.");
    }

    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSubMeshOperation(const SubMesh* sm)
    {
        // Header
        writeChunkHeader(M_SUBMESH_OPERATION, calcSubMeshOperationSize(sm));

        // unsigned short operationType
        unsigned short opType = static_cast<unsigned short>(sm->operationType);
        writeShorts(&opType, 1);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeGeometry(const VertexData* vertexData)
    {
            // calc size
        const VertexDeclaration::VertexElementList& elemList =
            vertexData->vertexDeclaration->getElements();
        const VertexBufferBinding::VertexBufferBindingMap& bindings =
            vertexData->vertexBufferBinding->getBindings();
        VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbiend;

            size_t size = STREAM_OVERHEAD_SIZE + sizeof(unsigned int) + // base
                  (STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5)); // elements
        vbiend = bindings.end();
            for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
            {
                  const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
                  size += (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
            }

            // Header
        writeChunkHeader(M_GEOMETRY, size);

        unsigned int vertexCount = vertexData->vertexCount;
        writeInts(&vertexCount, 1);

            // Vertex declaration
            size = STREAM_OVERHEAD_SIZE + elemList.size() * (STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5);
            writeChunkHeader(M_GEOMETRY_VERTEX_DECLARATION, size);

        VertexDeclaration::VertexElementList::const_iterator vei, veiend;
            veiend = elemList.end();
            unsigned short tmp;
            size = STREAM_OVERHEAD_SIZE + sizeof(unsigned short) * 5;
            for (vei = elemList.begin(); vei != veiend; ++vei)
            {
                  const VertexElement& elem = *vei;
                  writeChunkHeader(M_GEOMETRY_VERTEX_ELEMENT, size);
                  // unsigned short source;     // buffer bind source
                  tmp = elem.getSource();
                  writeShorts(&tmp, 1);
                  // unsigned short type;       // VertexElementType
                  tmp = static_cast<unsigned short>(elem.getType());
                  writeShorts(&tmp, 1);
                  // unsigned short semantic; // VertexElementSemantic
                  tmp = static_cast<unsigned short>(elem.getSemantic());
                  writeShorts(&tmp, 1);
                  // unsigned short offset;     // start offset in buffer in bytes
                  tmp = static_cast<unsigned short>(elem.getOffset());
                  writeShorts(&tmp, 1);
                  // unsigned short index;      // index of the semantic (for colours and texture coords)
                  tmp = elem.getIndex();
                  writeShorts(&tmp, 1);

            }

            // Buffers and bindings
            vbiend = bindings.end();
            for (vbi = bindings.begin(); vbi != vbiend; ++vbi)
            {
                  const HardwareVertexBufferSharedPtr& vbuf = vbi->second;
                  size = (STREAM_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vbuf->getSizeInBytes();
                  writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER,  size);
                  // unsigned short bindIndex;  // Index to bind this buffer to
                  tmp = vbi->first;
                  writeShorts(&tmp, 1);
                  // unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
                  tmp = (unsigned short)vbuf->getVertexSize();
                  writeShorts(&tmp, 1);

                  // Data
                  size = STREAM_OVERHEAD_SIZE + vbuf->getSizeInBytes();
                  writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size);
                  void* pBuf = vbuf->lock(HardwareBuffer::HBL_READ_ONLY);

                  if (mFlipEndian)
                  {
                        // endian conversion
                        // Copy data
                        unsigned char* tempData = new unsigned char[vbuf->getSizeInBytes()];
                        memcpy(tempData, pBuf, vbuf->getSizeInBytes());
                        flipToLittleEndian(
                              tempData,
                              vertexData->vertexCount,
                              vbuf->getVertexSize(),
                              vertexData->vertexDeclaration->findElementsBySource(vbi->first));
                        writeData(tempData, vbuf->getVertexSize(), vertexData->vertexCount);
                        delete [] tempData;
                  }
                  else
                  {
                        writeData(pBuf, vbuf->getVertexSize(), vertexData->vertexCount);
                  }
            vbuf->unlock();
            }


    }
    //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcSubMeshNameTableSize(const Mesh* pMesh)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // Figure out the size of the Name table.
            // Iterate through the subMeshList & add up the size of the indexes and names.
            Mesh::SubMeshNameMap::const_iterator it = pMesh->mSubMeshNameMap.begin();
            while(it != pMesh->mSubMeshNameMap.end())
            {
                  // size of the index + header size for each element chunk
                  size += STREAM_OVERHEAD_SIZE + sizeof(uint16);
                  // name
                  size += it->first.length() + 1;

                  ++it;
            }

            // size of the sub-mesh name table.
            return size;
      }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcMeshSize(const Mesh* pMesh)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // Num shared vertices
        size += sizeof(uint32);

        // Geometry
        if (pMesh->sharedVertexData && pMesh->sharedVertexData->vertexCount > 0)
        {
            size += calcGeometrySize(pMesh->sharedVertexData);
        }

        // Submeshes
        for (unsigned short i = 0; i < pMesh->getNumSubMeshes(); ++i)
        {
            size += calcSubMeshSize(pMesh->getSubMesh(i));
        }

        // Skeleton link
        if (pMesh->hasSkeleton())
        {
            size += calcSkeletonLinkSize(pMesh->getSkeletonName());
        }

            // Submesh name table
            size += calcSubMeshNameTableSize(pMesh);

            // Edge list
            if (pMesh->isEdgeListBuilt())
            {
                  size += calcEdgeListSize(pMesh);
            }

            // Animations
            for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
            {
                  Animation* anim = pMesh->getAnimation(a);
                  size += calcAnimationSize(anim);
            }

            return size;
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcSubMeshSize(const SubMesh* pSub)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // Material name
        size += pSub->getMaterialName().length() + 1;

        // bool useSharedVertices
        size += sizeof(bool);
        // unsigned int indexCount
        size += sizeof(unsigned int);
        // bool indexes32bit
        size += sizeof(bool);
        // unsigned int* faceVertexIndices
        size += sizeof(unsigned int) * pSub->indexData->indexCount;

        // Geometry
        if (!pSub->useSharedVertices)
        {
            size += calcGeometrySize(pSub->vertexData);
        }

        size += calcSubMeshTextureAliasesSize(pSub);
        size += calcSubMeshOperationSize(pSub);

        // Bone assignments
        if (!pSub->mBoneAssignments.empty())
        {
            SubMesh::VertexBoneAssignmentList::const_iterator vi;
            for (vi = pSub->mBoneAssignments.begin();
                 vi != pSub->mBoneAssignments.end(); ++vi)
            {
                size += calcBoneAssignmentSize();
            }
        }

        return size;
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcSubMeshOperationSize(const SubMesh* pSub)
    {
        return STREAM_OVERHEAD_SIZE + sizeof(uint16);
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcSubMeshTextureAliasesSize(const SubMesh* pSub)
    {
        size_t chunkSize = 0;
        AliasTextureNamePairList::const_iterator i;

        // iterate through texture alias map and calc size of strings
        for (i = pSub->mTextureAliases.begin(); i != pSub->mTextureAliases.end(); ++i)
        {
            // calculate chunk size based on string length + 1.  Add 1 for the line feed.
            chunkSize += STREAM_OVERHEAD_SIZE + i->first.length() + i->second.length() + 2;
        }

        return chunkSize;
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcGeometrySize(const VertexData* vertexData)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // Num vertices
        size += sizeof(unsigned int);

        const VertexDeclaration::VertexElementList& elems =
            vertexData->vertexDeclaration->getElements();

        VertexDeclaration::VertexElementList::const_iterator i, iend;
        iend = elems.end();
        for (i = elems.begin(); i != iend; ++i)
        {
            const VertexElement& elem = *i;
            // Vertex element
            size += VertexElement::getTypeSize(elem.getType()) * vertexData->vertexCount;
        }
        return size;
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
        VertexData* dest)
    {

        dest->vertexStart = 0;

        unsigned int vertexCount = 0;
        readInts(stream, &vertexCount, 1);
        dest->vertexCount = vertexCount;

        // Find optional geometry streams
        if (!stream->eof())
        {
            unsigned short streamID = readChunk(stream);
            while(!stream->eof() &&
                (streamID == M_GEOMETRY_VERTEX_DECLARATION ||
                 streamID == M_GEOMETRY_VERTEX_BUFFER ))
            {
                switch (streamID)
                {
                case M_GEOMETRY_VERTEX_DECLARATION:
                    readGeometryVertexDeclaration(stream, pMesh, dest);
                    break;
                case M_GEOMETRY_VERTEX_BUFFER:
                    readGeometryVertexBuffer(stream, pMesh, dest);
                    break;
                }
                // Get next stream
                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }
            }
            if (!stream->eof())
            {
                // Backpedal back to start of non-submesh stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }

            // Perform any necessary colour conversion for an active rendersystem
            if (Root::getSingletonPtr() && Root::getSingleton().getRenderSystem())
            {
                  // We don't know the source type if it's VET_COLOUR, but assume ARGB
                  // since that's the most common. Won't get used unless the mesh is
                  // ambiguous anyway, which will have been warned about in the log
                  dest->convertPackedColour(VET_COLOUR_ARGB, 
                        VertexElement::getBestColourVertexElementType());
            }
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readGeometryVertexDeclaration(DataStreamPtr& stream,
        Mesh* pMesh, VertexData* dest)
    {
        // Find optional geometry streams
        if (!stream->eof())
        {
            unsigned short streamID = readChunk(stream);
            while(!stream->eof() &&
                (streamID == M_GEOMETRY_VERTEX_ELEMENT ))
            {
                switch (streamID)
                {
                case M_GEOMETRY_VERTEX_ELEMENT:
                    readGeometryVertexElement(stream, pMesh, dest);
                    break;
                }
                // Get next stream
                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }
            }
            if (!stream->eof())
            {
                // Backpedal back to start of non-submesh stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }

      }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readGeometryVertexElement(DataStreamPtr& stream,
        Mesh* pMesh, VertexData* dest)
    {
            unsigned short source, offset, index, tmp;
            VertexElementType vType;
            VertexElementSemantic vSemantic;
            // unsigned short source;     // buffer bind source
            readShorts(stream, &source, 1);
            // unsigned short type;       // VertexElementType
            readShorts(stream, &tmp, 1);
            vType = static_cast<VertexElementType>(tmp);
            // unsigned short semantic; // VertexElementSemantic
            readShorts(stream, &tmp, 1);
            vSemantic = static_cast<VertexElementSemantic>(tmp);
            // unsigned short offset;     // start offset in buffer in bytes
            readShorts(stream, &offset, 1);
            // unsigned short index;      // index of the semantic
            readShorts(stream, &index, 1);

            dest->vertexDeclaration->addElement(source, offset, vType, vSemantic, index);

            if (vType == VET_COLOUR)
            {
                  StringUtil::StrStreamType s;
                  s << "Warning: VET_COLOUR element type is deprecated, you should use "
                        << "one of the more specific types to indicate the byte order. "
                        << "Use OgreMeshUpgrade on " << pMesh->getName() << " as soon as possible. ";
                  LogManager::getSingleton().logMessage(s.str());
            }

      }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readGeometryVertexBuffer(DataStreamPtr& stream,
        Mesh* pMesh, VertexData* dest)
    {
            unsigned short bindIndex, vertexSize;
            // unsigned short bindIndex;  // Index to bind this buffer to
            readShorts(stream, &bindIndex, 1);
            // unsigned short vertexSize; // Per-vertex size, must agree with declaration at this index
            readShorts(stream, &vertexSize, 1);

            // Check for vertex data header
            unsigned short headerID;
            headerID = readChunk(stream);
            if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA)
            {
                  OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Can't find vertex buffer data area",
                  "MeshSerializerImpl::readGeometryVertexBuffer");
            }
            // Check that vertex size agrees
            if (dest->vertexDeclaration->getVertexSize(bindIndex) != vertexSize)
            {
                  OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer vertex size does not agree with vertex declaration",
                  "MeshSerializerImpl::readGeometryVertexBuffer");
            }

            // Create / populate vertex buffer
            HardwareVertexBufferSharedPtr vbuf;
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            vertexSize,
            dest->vertexCount,
            pMesh->mVertexBufferUsage,
                  pMesh->mVertexBufferShadowBuffer);
        void* pBuf = vbuf->lock(HardwareBuffer::HBL_DISCARD);
        stream->read(pBuf, dest->vertexCount * vertexSize);

            // endian conversion for OSX
            flipFromLittleEndian(
                  pBuf,
                  dest->vertexCount,
                  vertexSize,
                  dest->vertexDeclaration->findElementsBySource(bindIndex));
        vbuf->unlock();

            // Set binding
        dest->vertexBufferBinding->setBinding(bindIndex, vbuf);

      }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::readSubMeshNameTable(DataStreamPtr& stream, Mesh* pMesh)
      {
            // The map for
            std::map<unsigned short, String> subMeshNames;
            unsigned short streamID, subMeshIndex;

            // Need something to store the index, and the objects name
            // This table is a method that imported meshes can retain their naming
            // so that the names established in the modelling software can be used
            // to get the sub-meshes by name. The exporter must support exporting
            // the optional stream M_SUBMESH_NAME_TABLE.

        // Read in all the sub-streams. Each sub-stream should contain an index and Ogre::String for the name.
            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() && (streamID == M_SUBMESH_NAME_TABLE_ELEMENT ))
                  {
                        // Read in the index of the submesh.
                        readShorts(stream, &subMeshIndex, 1);
                        // Read in the String and map it to its index.
                        subMeshNames[subMeshIndex] = readString(stream);

                        // If we're not end of file get the next stream ID
                        if (!stream->eof())
                              streamID = readChunk(stream);
                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }

            // Set all the submeshes names
            // ?

            // Loop through and save out the index and names.
            std::map<unsigned short, String>::const_iterator it = subMeshNames.begin();

            while(it != subMeshNames.end())
            {
                  // Name this submesh to the stored name.
                  pMesh->nameSubMesh(it->second, it->first);
                  ++it;
            }



      }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readMesh(DataStreamPtr& stream, Mesh* pMesh)
    {
        unsigned short streamID;

        // Never automatically build edge lists for this version
        // expect them in the file or not at all
        pMesh->mAutoBuildEdgeLists = false;

            // bool skeletallyAnimated
            bool skeletallyAnimated;
            readBools(stream, &skeletallyAnimated, 1);

        // Find all substreams
        if (!stream->eof())
        {
            streamID = readChunk(stream);
            while(!stream->eof() &&
                (streamID == M_GEOMETRY ||
                         streamID == M_SUBMESH ||
                 streamID == M_MESH_SKELETON_LINK ||
                 streamID == M_MESH_BONE_ASSIGNMENT ||
                         streamID == M_MESH_LOD ||
                 streamID == M_MESH_BOUNDS ||
                         streamID == M_SUBMESH_NAME_TABLE ||
                         streamID == M_EDGE_LISTS ||
                         streamID == M_POSES ||
                         streamID == M_ANIMATIONS ||
                         streamID == M_TABLE_EXTREMES))
            {
                switch(streamID)
                {
                        case M_GEOMETRY:
                              pMesh->sharedVertexData = new VertexData();
                              try {
                                    readGeometry(stream, pMesh, pMesh->sharedVertexData);
                              }
                              catch (Exception& e)
                              {
                                    if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
                                    {
                                          // duff geometry data entry with 0 vertices
                                          delete pMesh->sharedVertexData;
                                          pMesh->sharedVertexData = 0;
                                          // Skip this stream (pointer will have been returned to just after header)
                                          stream->skip(mCurrentstreamLen - STREAM_OVERHEAD_SIZE);
                                    }
                                    else
                                    {
                                          throw;
                                    }
                              }
                              break;
                case M_SUBMESH:
                    readSubMesh(stream, pMesh);
                    break;
                case M_MESH_SKELETON_LINK:
                    readSkeletonLink(stream, pMesh);
                    break;
                case M_MESH_BONE_ASSIGNMENT:
                    readMeshBoneAssignment(stream, pMesh);
                    break;
                case M_MESH_LOD:
                              readMeshLodInfo(stream, pMesh);
                              break;
                case M_MESH_BOUNDS:
                    readBoundsInfo(stream, pMesh);
                    break;
                        case M_SUBMESH_NAME_TABLE:
                  readSubMeshNameTable(stream, pMesh);
                              break;
                case M_EDGE_LISTS:
                    readEdgeList(stream, pMesh);
                    break;
                        case M_POSES:
                              readPoses(stream, pMesh);
                              break;
                        case M_ANIMATIONS:
                              readAnimations(stream, pMesh);
                    break;
                case M_TABLE_EXTREMES:
                    readExtremes(stream, pMesh);
                    break;
                }

                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }

            }
            if (!stream->eof())
            {
                // Backpedal back to start of stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readSubMesh(DataStreamPtr& stream, Mesh* pMesh)
    {
        unsigned short streamID;

        SubMesh* sm = pMesh->createSubMesh();
        // char* materialName
        String materialName = readString(stream);
        sm->setMaterialName(materialName);
        // bool useSharedVertices
        readBools(stream,&sm->useSharedVertices, 1);

        sm->indexData->indexStart = 0;
        unsigned int indexCount = 0;
        readInts(stream, &indexCount, 1);
        sm->indexData->indexCount = indexCount;

        HardwareIndexBufferSharedPtr ibuf;
        // bool indexes32Bit
        bool idx32bit;
        readBools(stream, &idx32bit, 1);
        if (idx32bit)
        {
            ibuf = HardwareBufferManager::getSingleton().
                createIndexBuffer(
                    HardwareIndexBuffer::IT_32BIT,
                    sm->indexData->indexCount,
                    pMesh->mIndexBufferUsage,
                              pMesh->mIndexBufferShadowBuffer);
            // unsigned int* faceVertexIndices
            unsigned int* pIdx = static_cast<unsigned int*>(
                ibuf->lock(HardwareBuffer::HBL_DISCARD)
                );
            readInts(stream, pIdx, sm->indexData->indexCount);
            ibuf->unlock();

        }
        else // 16-bit
        {
            ibuf = HardwareBufferManager::getSingleton().
                createIndexBuffer(
                    HardwareIndexBuffer::IT_16BIT,
                    sm->indexData->indexCount,
                    pMesh->mIndexBufferUsage,
                              pMesh->mIndexBufferShadowBuffer);
            // unsigned short* faceVertexIndices
            unsigned short* pIdx = static_cast<unsigned short*>(
                ibuf->lock(HardwareBuffer::HBL_DISCARD)
                );
            readShorts(stream, pIdx, sm->indexData->indexCount);
            ibuf->unlock();
        }
        sm->indexData->indexBuffer = ibuf;

        // M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
        if (!sm->useSharedVertices)
        {
            streamID = readChunk(stream);
            if (streamID != M_GEOMETRY)
            {
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file",
                    "MeshSerializerImpl::readSubMesh");
            }
            sm->vertexData = new VertexData();
            readGeometry(stream, pMesh, sm->vertexData);
        }


        // Find all bone assignments, submesh operation, and texture aliases (if present)
        if (!stream->eof())
        {
            streamID = readChunk(stream);
            while(!stream->eof() &&
                (streamID == M_SUBMESH_BONE_ASSIGNMENT ||
                 streamID == M_SUBMESH_OPERATION ||
                 streamID == M_SUBMESH_TEXTURE_ALIAS))
            {
                switch(streamID)
                {
                case M_SUBMESH_OPERATION:
                    readSubMeshOperation(stream, pMesh, sm);
                    break;
                case M_SUBMESH_BONE_ASSIGNMENT:
                    readSubMeshBoneAssignment(stream, pMesh, sm);
                    break;
                case M_SUBMESH_TEXTURE_ALIAS:
                    readSubMeshTextureAlias(stream, pMesh, sm);
                    break;
                }

                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }

            }
            if (!stream->eof())
            {
                // Backpedal back to start of stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readSubMeshOperation(DataStreamPtr& stream,
        Mesh* pMesh, SubMesh* sm)
    {
        // unsigned short operationType
        unsigned short opType;
        readShorts(stream, &opType, 1);
        sm->operationType = static_cast<RenderOperation::OperationType>(opType);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readSubMeshTextureAlias(DataStreamPtr& stream, Mesh* pMesh, SubMesh* sub)
    {
        String aliasName = readString(stream);
        String textureName = readString(stream);
        sub->addTextureAlias(aliasName, textureName);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSkeletonLink(const String& skelName)
    {
        writeChunkHeader(M_MESH_SKELETON_LINK, calcSkeletonLinkSize(skelName));

        writeString(skelName);

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readSkeletonLink(DataStreamPtr& stream, Mesh* pMesh)
    {
        String skelName = readString(stream);
        pMesh->setSkeletonName(skelName);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readTextureLayer(DataStreamPtr& stream, Mesh* pMesh,
        MaterialPtr& pMat)
    {
        // Material definition section phased out of 1.1
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcSkeletonLinkSize(const String& skelName)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        size += skelName.length() + 1;

        return size;

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeMeshBoneAssignment(const VertexBoneAssignment& assign)
    {
        writeChunkHeader(M_MESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());

        // unsigned int vertexIndex;
        writeInts(&(assign.vertexIndex), 1);
        // unsigned short boneIndex;
        writeShorts(&(assign.boneIndex), 1);
        // float weight;
        writeFloats(&(assign.weight), 1);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeSubMeshBoneAssignment(const VertexBoneAssignment& assign)
    {
        writeChunkHeader(M_SUBMESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());

        // unsigned int vertexIndex;
        writeInts(&(assign.vertexIndex), 1);
        // unsigned short boneIndex;
        writeShorts(&(assign.boneIndex), 1);
        // float weight;
        writeFloats(&(assign.weight), 1);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readMeshBoneAssignment(DataStreamPtr& stream, Mesh* pMesh)
    {
        VertexBoneAssignment assign;

        // unsigned int vertexIndex;
        readInts(stream, &(assign.vertexIndex),1);
        // unsigned short boneIndex;
        readShorts(stream, &(assign.boneIndex),1);
        // float weight;
        readFloats(stream, &(assign.weight), 1);

        pMesh->addBoneAssignment(assign);

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readSubMeshBoneAssignment(DataStreamPtr& stream,
        Mesh* pMesh, SubMesh* sub)
    {
        VertexBoneAssignment assign;

        // unsigned int vertexIndex;
        readInts(stream, &(assign.vertexIndex),1);
        // unsigned short boneIndex;
        readShorts(stream, &(assign.boneIndex),1);
        // float weight;
        readFloats(stream, &(assign.weight), 1);

        sub->addBoneAssignment(assign);

    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcBoneAssignmentSize(void)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // Vert index
        size += sizeof(unsigned int);
        // Bone index
        size += sizeof(unsigned short);
        // weight
        size += sizeof(float);

        return size;
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeLodInfo(const Mesh* pMesh)
    {
        unsigned short numLods = pMesh->getNumLodLevels();
        bool manual = pMesh->isLodManual();
        writeLodSummary(numLods, manual);

            // Loop from LOD 1 (not 0, this is full detail)
        for (unsigned short i = 1; i < numLods; ++i)
        {
                  const MeshLodUsage& usage = pMesh->getLodLevel(i);
                  if (manual)
                  {
                        writeLodUsageManual(usage);
                  }
                  else
                  {
                        writeLodUsageGenerated(pMesh, usage, i);
                  }

        }


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeLodSummary(unsigned short numLevels, bool manual)
    {
        // Header
        size_t size = STREAM_OVERHEAD_SIZE;
        // unsigned short numLevels;
        size += sizeof(unsigned short);
        // bool manual;  (true for manual alternate meshes, false for generated)
        size += sizeof(bool);
        writeChunkHeader(M_MESH_LOD, size);

        // Details
        // unsigned short numLevels;
        writeShorts(&numLevels, 1);
        // bool manual;  (true for manual alternate meshes, false for generated)
        writeBools(&manual, 1);


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeLodUsageManual(const MeshLodUsage& usage)
    {
        // Header
        size_t size = STREAM_OVERHEAD_SIZE;
        size_t manualSize = STREAM_OVERHEAD_SIZE;
        // float fromDepthSquared;
        size += sizeof(float);
        // Manual part size

        // String manualMeshName;
        manualSize += usage.manualName.length() + 1;

        size += manualSize;

        writeChunkHeader(M_MESH_LOD_USAGE, size);
        writeFloats(&(usage.fromDepthSquared), 1);

        writeChunkHeader(M_MESH_LOD_MANUAL, manualSize);
        writeString(usage.manualName);


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeLodUsageGenerated(const Mesh* pMesh, const MeshLodUsage& usage,
            unsigned short lodNum)
    {
            // Usage Header
        size_t size = STREAM_OVERHEAD_SIZE;
            unsigned short subidx;

        // float fromDepthSquared;
        size += sizeof(float);

        // Calc generated SubMesh sections size
            for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
            {
                  // header
                  size += STREAM_OVERHEAD_SIZE;
                  // unsigned int numFaces;
                  size += sizeof(unsigned int);
                  SubMesh* sm = pMesh->getSubMesh(subidx);
            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];

            // bool indexes32Bit
                  size += sizeof(bool);
                  // unsigned short*/int* faceIndexes;
            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
            {
                      size += static_cast<unsigned long>(
                    sizeof(unsigned int) * indexData->indexCount);
            }
            else
            {
                      size += static_cast<unsigned long>(
                    sizeof(unsigned short) * indexData->indexCount);
            }

            }

        writeChunkHeader(M_MESH_LOD_USAGE, size);
        writeFloats(&(usage.fromDepthSquared), 1);

            // Now write sections
        // Calc generated SubMesh sections size
            for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
            {
                  size = STREAM_OVERHEAD_SIZE;
                  // unsigned int numFaces;
                  size += sizeof(unsigned int);
                  SubMesh* sm = pMesh->getSubMesh(subidx);
            const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
            // bool indexes32Bit
                  size += sizeof(bool);
                  // unsigned short*/int* faceIndexes;
            if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
            {
                      size += static_cast<unsigned long>(
                    sizeof(unsigned int) * indexData->indexCount);
            }
            else
            {
                      size += static_cast<unsigned long>(
                    sizeof(unsigned short) * indexData->indexCount);
            }

                  writeChunkHeader(M_MESH_LOD_GENERATED, size);
                  unsigned int idxCount = static_cast<unsigned int>(indexData->indexCount);
                  writeInts(&idxCount, 1);
            // Lock index buffer to write
            HardwareIndexBufferSharedPtr ibuf = indexData->indexBuffer;
                  // bool indexes32bit
                  bool idx32 = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
                  writeBools(&idx32, 1);
            if (idx32)
            {
                unsigned int* pIdx = static_cast<unsigned int*>(
                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
                      writeInts(pIdx, indexData->indexCount);
                ibuf->unlock();
            }
            else
            {
                unsigned short* pIdx = static_cast<unsigned short*>(
                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
                      writeShorts(pIdx, indexData->indexCount);
                ibuf->unlock();
            }
            }


    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::writeBoundsInfo(const Mesh* pMesh)
    {
            // Usage Header
        unsigned long size = STREAM_OVERHEAD_SIZE;

        size += sizeof(float) * 7;
        writeChunkHeader(M_MESH_BOUNDS, size);

        // float minx, miny, minz
        const Vector3& min = pMesh->mAABB.getMinimum();
        const Vector3& max = pMesh->mAABB.getMaximum();
        writeFloats(&min.x, 1);
        writeFloats(&min.y, 1);
        writeFloats(&min.z, 1);
        // float maxx, maxy, maxz
        writeFloats(&max.x, 1);
        writeFloats(&max.y, 1);
        writeFloats(&max.z, 1);
        // float radius
        writeFloats(&pMesh->mBoundRadius, 1);

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl::readBoundsInfo(DataStreamPtr& stream, Mesh* pMesh)
    {
        Vector3 min, max;
        // float minx, miny, minz
        readFloats(stream, &min.x, 1);
        readFloats(stream, &min.y, 1);
        readFloats(stream, &min.z, 1);
        // float maxx, maxy, maxz
        readFloats(stream, &max.x, 1);
        readFloats(stream, &max.y, 1);
        readFloats(stream, &max.z, 1);
        AxisAlignedBox box(min, max);
        pMesh->_setBounds(box, true);
        // float radius
        float radius;
        readFloats(stream, &radius, 1);
        pMesh->_setBoundingSphereRadius(radius);



    }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::readMeshLodInfo(DataStreamPtr& stream, Mesh* pMesh)
      {
            unsigned short streamID, i;

        // unsigned short numLevels;
            readShorts(stream, &(pMesh->mNumLods), 1);
        // bool manual;  (true for manual alternate meshes, false for generated)
            readBools(stream, &(pMesh->mIsLodManual), 1);

            // Preallocate submesh lod face data if not manual
            if (!pMesh->mIsLodManual)
            {
                  unsigned short numsubs = pMesh->getNumSubMeshes();
                  for (i = 0; i < numsubs; ++i)
                  {
                        SubMesh* sm = pMesh->getSubMesh(i);
                        sm->mLodFaceList.resize(pMesh->mNumLods-1);
                  }
            }

            // Loop from 1 rather than 0 (full detail index is not in file)
            for (i = 1; i < pMesh->mNumLods; ++i)
            {
                  streamID = readChunk(stream);
                  if (streamID != M_MESH_LOD_USAGE)
                  {
                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                              "Missing M_MESH_LOD_USAGE stream in " + pMesh->getName(),
                              "MeshSerializerImpl::readMeshLodInfo");
                  }
                  // Read depth
                  MeshLodUsage usage;
                  readFloats(stream, &(usage.fromDepthSquared), 1);

                  if (pMesh->isLodManual())
                  {
                        readMeshLodUsageManual(stream, pMesh, i, usage);
                  }
                  else //(!pMesh->isLodManual)
                  {
                        readMeshLodUsageGenerated(stream, pMesh, i, usage);
                  }
            usage.edgeData = NULL;

                  // Save usage
                  pMesh->mMeshLodUsageList.push_back(usage);
            }


      }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::readMeshLodUsageManual(DataStreamPtr& stream,
        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
      {
            unsigned long streamID;
            // Read detail stream
            streamID = readChunk(stream);
            if (streamID != M_MESH_LOD_MANUAL)
            {
                  OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                        "Missing M_MESH_LOD_MANUAL stream in " + pMesh->getName(),
                        "MeshSerializerImpl::readMeshLodUsageManual");
            }

            usage.manualName = readString(stream);
            usage.manualMesh.setNull(); // will trigger load later
      }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::readMeshLodUsageGenerated(DataStreamPtr& stream,
        Mesh* pMesh, unsigned short lodNum, MeshLodUsage& usage)
      {
            usage.manualName = "";
            usage.manualMesh.setNull();

            // Get one set of detail per SubMesh
            unsigned short numSubs, i;
            unsigned long streamID;
            numSubs = pMesh->getNumSubMeshes();
            for (i = 0; i < numSubs; ++i)
            {
                  streamID = readChunk(stream);
                  if (streamID != M_MESH_LOD_GENERATED)
                  {
                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
                              "Missing M_MESH_LOD_GENERATED stream in " + pMesh->getName(),
                              "MeshSerializerImpl::readMeshLodUsageGenerated");
                  }

                  SubMesh* sm = pMesh->getSubMesh(i);
                  // lodNum - 1 because SubMesh doesn't store full detail LOD
            sm->mLodFaceList[lodNum - 1] = new IndexData();
                  IndexData* indexData = sm->mLodFaceList[lodNum - 1];
            // unsigned int numIndexes
            unsigned int numIndexes;
                  readInts(stream, &numIndexes, 1);
            indexData->indexCount = static_cast<size_t>(numIndexes);
            // bool indexes32Bit
            bool idx32Bit;
            readBools(stream, &idx32Bit, 1);
            // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
            if (idx32Bit)
            {
                indexData->indexBuffer = HardwareBufferManager::getSingleton().
                    createIndexBuffer(HardwareIndexBuffer::IT_32BIT, indexData->indexCount,
                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
                unsigned int* pIdx = static_cast<unsigned int*>(
                    indexData->indexBuffer->lock(
                        0,
                        indexData->indexBuffer->getSizeInBytes(),
                        HardwareBuffer::HBL_DISCARD) );

                      readInts(stream, pIdx, indexData->indexCount);
                indexData->indexBuffer->unlock();

            }
            else
            {
                indexData->indexBuffer = HardwareBufferManager::getSingleton().
                    createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
                    pMesh->mIndexBufferUsage, pMesh->mIndexBufferShadowBuffer);
                unsigned short* pIdx = static_cast<unsigned short*>(
                    indexData->indexBuffer->lock(
                        0,
                        indexData->indexBuffer->getSizeInBytes(),
                        HardwareBuffer::HBL_DISCARD) );
                      readShorts(stream, pIdx, indexData->indexCount);
                indexData->indexBuffer->unlock();

            }

            }
      }
    //---------------------------------------------------------------------
01477     void MeshSerializerImpl::flipFromLittleEndian(void* pData, size_t vertexCount,
        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
      {
            if (mFlipEndian)
            {
              flipEndian(pData, vertexCount, vertexSize, elems);
            }
    }
    //---------------------------------------------------------------------
01486     void MeshSerializerImpl::flipToLittleEndian(void* pData, size_t vertexCount,
                  size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
      {
            if (mFlipEndian)
            {
              flipEndian(pData, vertexCount, vertexSize, elems);
            }
      }
    //---------------------------------------------------------------------
01495     void MeshSerializerImpl::flipEndian(void* pData, size_t vertexCount,
        size_t vertexSize, const VertexDeclaration::VertexElementList& elems)
      {
            void *pBase = pData;
            for (size_t v = 0; v < vertexCount; ++v)
            {
                  VertexDeclaration::VertexElementList::const_iterator ei, eiend;
                  eiend = elems.end();
                  for (ei = elems.begin(); ei != eiend; ++ei)
                  {
                        void *pElem;
                        // re-base pointer to the element
                        (*ei).baseVertexPointerToElement(pBase, &pElem);
                        // Flip the endian based on the type
                        size_t typeSize = 0;
                        switch (VertexElement::getBaseType((*ei).getType()))
                        {
                              case VET_FLOAT1:
                                    typeSize = sizeof(float);
                                    break;
                              case VET_SHORT1:
                                    typeSize = sizeof(short);
                                    break;
                              case VET_COLOUR:
                              case VET_COLOUR_ABGR:
                              case VET_COLOUR_ARGB:
                                    typeSize = sizeof(RGBA);
                                    break;
                              case VET_UBYTE4:
                                    typeSize = 0; // NO FLIPPING
                                    break;
                              default:
                                    assert(false); // Should never happen
                        };
                Serializer::flipEndian(pElem, typeSize,
                              VertexElement::getTypeCount((*ei).getType()));

                  }

                  pBase = static_cast<void*>(
                        static_cast<unsigned char*>(pBase) + vertexSize);

            }
      }
    //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcEdgeListSize(const Mesh* pMesh)
      {
        size_t size = STREAM_OVERHEAD_SIZE;

        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
        {

            const EdgeData* edgeData = pMesh->getEdgeList(i);
            bool isManual = pMesh->isLodManual() && (i > 0);

            size += calcEdgeListLodSize(edgeData, isManual);

        }

        return size;
      }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcEdgeListLodSize(const EdgeData* edgeData, bool isManual)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // unsigned short lodIndex
        size += sizeof(uint16);

        // bool isManual                  // If manual, no edge data here, loaded from manual mesh
        size += sizeof(bool);
        if (!isManual)
        {
            // bool isClosed
            size += sizeof(bool);
            // unsigned long numTriangles
            size += sizeof(uint32);
            // unsigned long numEdgeGroups
            size += sizeof(uint32);
            // Triangle* triangleList
            size_t triSize = 0;
            // unsigned long indexSet
            // unsigned long vertexSet
            // unsigned long vertIndex[3]
            // unsigned long sharedVertIndex[3]
            // float normal[4]
            triSize += sizeof(uint32) * 8
                    + sizeof(float) * 4;

            size += triSize * edgeData->triangles.size();
            // Write the groups
            for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
                gi != edgeData->edgeGroups.end(); ++gi)
            {
                const EdgeData::EdgeGroup& edgeGroup = *gi;
                size += calcEdgeGroupSize(edgeGroup);
            }

        }

        return size;
    }
    //---------------------------------------------------------------------
    size_t MeshSerializerImpl::calcEdgeGroupSize(const EdgeData::EdgeGroup& group)
    {
        size_t size = STREAM_OVERHEAD_SIZE;

        // unsigned long vertexSet
        size += sizeof(uint32);
        // unsigned long triStart
        size += sizeof(uint32);
        // unsigned long triCount
        size += sizeof(uint32);
        // unsigned long numEdges
        size += sizeof(uint32);
        // Edge* edgeList
        size_t edgeSize = 0;
        // unsigned long  triIndex[2]
        // unsigned long  vertIndex[2]
        // unsigned long  sharedVertIndex[2]
        // bool degenerate
        edgeSize += sizeof(uint32) * 6 + sizeof(bool);
        size += edgeSize * group.edges.size();

        return size;
    }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::writeEdgeList(const Mesh* pMesh)
      {
        writeChunkHeader(M_EDGE_LISTS, calcEdgeListSize(pMesh));

        for (ushort i = 0; i < pMesh->getNumLodLevels(); ++i)
        {
            const EdgeData* edgeData = pMesh->getEdgeList(i);
            bool isManual = pMesh->isLodManual() && (i > 0);
            writeChunkHeader(M_EDGE_LIST_LOD, calcEdgeListLodSize(edgeData, isManual));

            // unsigned short lodIndex
            writeShorts(&i, 1);

            // bool isManual              // If manual, no edge data here, loaded from manual mesh
            writeBools(&isManual, 1);
            if (!isManual)
            {
                // bool isClosed
                writeBools(&edgeData->isClosed, 1);
                // unsigned long  numTriangles
                uint32 count = static_cast<uint32>(edgeData->triangles.size());
                writeInts(&count, 1);
                // unsigned long numEdgeGroups
                count = static_cast<uint32>(edgeData->edgeGroups.size());
                writeInts(&count, 1);
                // Triangle* triangleList
                // Iterate rather than writing en-masse to allow endian conversion
                EdgeData::TriangleList::const_iterator t = edgeData->triangles.begin();
                EdgeData::TriangleFaceNormalList::const_iterator fni = edgeData->triangleFaceNormals.begin();
                for ( ; t != edgeData->triangles.end(); ++t, ++fni)
                {
                    const EdgeData::Triangle& tri = *t;
                    // unsigned long indexSet;
                    uint32 tmp[3];
                    tmp[0] = tri.indexSet;
                    writeInts(tmp, 1);
                    // unsigned long vertexSet;
                    tmp[0] = tri.vertexSet;
                    writeInts(tmp, 1);
                    // unsigned long vertIndex[3];
                    tmp[0] = tri.vertIndex[0];
                    tmp[1] = tri.vertIndex[1];
                    tmp[2] = tri.vertIndex[2];
                    writeInts(tmp, 3);
                    // unsigned long sharedVertIndex[3];
                    tmp[0] = tri.sharedVertIndex[0];
                    tmp[1] = tri.sharedVertIndex[1];
                    tmp[2] = tri.sharedVertIndex[2];
                    writeInts(tmp, 3);
                    // float normal[4];
                    writeFloats(&(fni->x), 4);

                }
                // Write the groups
                for (EdgeData::EdgeGroupList::const_iterator gi = edgeData->edgeGroups.begin();
                    gi != edgeData->edgeGroups.end(); ++gi)
                {
                    const EdgeData::EdgeGroup& edgeGroup = *gi;
                    writeChunkHeader(M_EDGE_GROUP, calcEdgeGroupSize(edgeGroup));
                    // unsigned long vertexSet
                    uint32 vertexSet = static_cast<uint32>(edgeGroup.vertexSet);
                    writeInts(&vertexSet, 1);
                    // unsigned long triStart
                    uint32 triStart = static_cast<uint32>(edgeGroup.triStart);
                    writeInts(&triStart, 1);
                    // unsigned long triCount
                    uint32 triCount = static_cast<uint32>(edgeGroup.triCount);
                    writeInts(&triCount, 1);
                    // unsigned long numEdges
                    count = static_cast<uint32>(edgeGroup.edges.size());
                    writeInts(&count, 1);
                    // Edge* edgeList
                    // Iterate rather than writing en-masse to allow endian conversion
                    for (EdgeData::EdgeList::const_iterator ei = edgeGroup.edges.begin();
                        ei != edgeGroup.edges.end(); ++ei)
                    {
                        const EdgeData::Edge& edge = *ei;
                        uint32 tmp[2];
                        // unsigned long  triIndex[2]
                        tmp[0] = edge.triIndex[0];
                        tmp[1] = edge.triIndex[1];
                        writeInts(tmp, 2);
                        // unsigned long  vertIndex[2]
                        tmp[0] = edge.vertIndex[0];
                        tmp[1] = edge.vertIndex[1];
                        writeInts(tmp, 2);
                        // unsigned long  sharedVertIndex[2]
                        tmp[0] = edge.sharedVertIndex[0];
                        tmp[1] = edge.sharedVertIndex[1];
                        writeInts(tmp, 2);
                        // bool degenerate
                        writeBools(&(edge.degenerate), 1);
                    }

                }

            }

        }
      }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::readEdgeList(DataStreamPtr& stream, Mesh* pMesh)
      {
        unsigned short streamID;

        if (!stream->eof())
        {
            streamID = readChunk(stream);
            while(!stream->eof() &&
                streamID == M_EDGE_LIST_LOD)
            {
                // Process single LOD

                // unsigned short lodIndex
                unsigned short lodIndex;
                readShorts(stream, &lodIndex, 1);

                // bool isManual                // If manual, no edge data here, loaded from manual mesh
                bool isManual;
                readBools(stream, &isManual, 1);
                // Only load in non-manual levels; others will be connected up by Mesh on demand
                if (!isManual)
                {
                    MeshLodUsage& usage = const_cast<MeshLodUsage&>(pMesh->getLodLevel(lodIndex));

                    usage.edgeData = new EdgeData();

                    // Read detail information of the edge list
                    readEdgeListLodInfo(stream, usage.edgeData);

                    // Postprocessing edge groups
                    EdgeData::EdgeGroupList::iterator egi, egend;
                    egend = usage.edgeData->edgeGroups.end();
                    for (egi = usage.edgeData->edgeGroups.begin(); egi != egend; ++egi)
                    {
                        EdgeData::EdgeGroup& edgeGroup = *egi;
                        // Populate edgeGroup.vertexData pointers
                        // If there is shared vertex data, vertexSet 0 is that,
                        // otherwise 0 is first dedicated
                        if (pMesh->sharedVertexData)
                        {
                            if (edgeGroup.vertexSet == 0)
                            {
                                edgeGroup.vertexData = pMesh->sharedVertexData;
                            }
                            else
                            {
                                edgeGroup.vertexData = pMesh->getSubMesh(
                                    edgeGroup.vertexSet-1)->vertexData;
                            }
                        }
                        else
                        {
                            edgeGroup.vertexData = pMesh->getSubMesh(
                                edgeGroup.vertexSet)->vertexData;
                        }
                    }
                }

                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }

            }
            if (!stream->eof())
            {
                // Backpedal back to start of stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }

        pMesh->mEdgeListsBuilt = true;
      }
      //---------------------------------------------------------------------
    void MeshSerializerImpl::readEdgeListLodInfo(DataStreamPtr& stream,
        EdgeData* edgeData)
    {
        // bool isClosed
        readBools(stream, &edgeData->isClosed, 1);
        // unsigned long numTriangles
        uint32 numTriangles;
        readInts(stream, &numTriangles, 1);
        // Allocate correct amount of memory
        edgeData->triangles.resize(numTriangles);
        edgeData->triangleFaceNormals.resize(numTriangles);
        edgeData->triangleLightFacings.resize(numTriangles);
        // unsigned long numEdgeGroups
        uint32 numEdgeGroups;
        readInts(stream, &numEdgeGroups, 1);
        // Allocate correct amount of memory
        edgeData->edgeGroups.resize(numEdgeGroups);
        // Triangle* triangleList
        uint32 tmp[3];
        for (size_t t = 0; t < numTriangles; ++t)
        {
            EdgeData::Triangle& tri = edgeData->triangles[t];
            // unsigned long indexSet
            readInts(stream, tmp, 1);
            tri.indexSet = tmp[0];
            // unsigned long vertexSet
            readInts(stream, tmp, 1);
            tri.vertexSet = tmp[0];
            // unsigned long vertIndex[3]
            readInts(stream, tmp, 3);
            tri.vertIndex[0] = tmp[0];
            tri.vertIndex[1] = tmp[1];
            tri.vertIndex[2] = tmp[2];
            // unsigned long sharedVertIndex[3]
            readInts(stream, tmp, 3);
            tri.sharedVertIndex[0] = tmp[0];
            tri.sharedVertIndex[1] = tmp[1];
            tri.sharedVertIndex[2] = tmp[2];
            // float normal[4]
            readFloats(stream, &(edgeData->triangleFaceNormals[t].x), 4);

        }

        for (uint32 eg = 0; eg < numEdgeGroups; ++eg)
        {
            unsigned short streamID = readChunk(stream);
            if (streamID != M_EDGE_GROUP)
            {
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                    "Missing M_EDGE_GROUP stream",
                    "MeshSerializerImpl::readEdgeListLodInfo");
            }
            EdgeData::EdgeGroup& edgeGroup = edgeData->edgeGroups[eg];

            // unsigned long vertexSet
            readInts(stream, tmp, 1);
            edgeGroup.vertexSet = tmp[0];
            // unsigned long triStart
            readInts(stream, tmp, 1);
            edgeGroup.triStart = tmp[0];
            // unsigned long triCount
            readInts(stream, tmp, 1);
            edgeGroup.triCount = tmp[0];
            // unsigned long numEdges
            uint32 numEdges;
            readInts(stream, &numEdges, 1);
            edgeGroup.edges.resize(numEdges);
            // Edge* edgeList
            for (uint32 e = 0; e < numEdges; ++e)
            {
                EdgeData::Edge& edge = edgeGroup.edges[e];
                // unsigned long  triIndex[2]
                readInts(stream, tmp, 2);
                edge.triIndex[0] = tmp[0];
                edge.triIndex[1] = tmp[1];
                // unsigned long  vertIndex[2]
                readInts(stream, tmp, 2);
                edge.vertIndex[0] = tmp[0];
                edge.vertIndex[1] = tmp[1];
                // unsigned long  sharedVertIndex[2]
                readInts(stream, tmp, 2);
                edge.sharedVertIndex[0] = tmp[0];
                edge.sharedVertIndex[1] = tmp[1];
                // bool degenerate
                readBools(stream, &(edge.degenerate), 1);
            }
        }
    }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcAnimationsSize(const Mesh* pMesh)
      {
            size_t size = STREAM_OVERHEAD_SIZE;

            for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
            {
                  Animation* anim = pMesh->getAnimation(a);
                  size += calcAnimationSize(anim);
            }
            return size;

      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcAnimationSize(const Animation* anim)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // char* name
            size += anim->getName().length() + 1;

            // float length
            size += sizeof(float);

            Animation::VertexTrackIterator trackIt = anim->getVertexTrackIterator();
            while (trackIt.hasMoreElements())
            {
                  VertexAnimationTrack* vt = trackIt.getNext();
                  size += calcAnimationTrackSize(vt);
            }

            return size;
      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcAnimationTrackSize(const VertexAnimationTrack* track)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // uint16 type
            size += sizeof(uint16);
            // unsigned short target            // 0 for shared geometry,
            size += sizeof(unsigned short);

            if (track->getAnimationType() == VAT_MORPH)
            {
                  for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
                  {
                        VertexMorphKeyFrame* kf = track->getVertexMorphKeyFrame(i);
                        size += calcMorphKeyframeSize(kf, track->getAssociatedVertexData()->vertexCount);
                  }
            }
            else
            {
                  for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
                  {
                        VertexPoseKeyFrame* kf = track->getVertexPoseKeyFrame(i);
                        size += calcPoseKeyframeSize(kf);
                  }
            }
            return size;
      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcMorphKeyframeSize(const VertexMorphKeyFrame* kf,
            size_t vertexCount)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // float time
            size += sizeof(float);
            // bool isOriginalGeometry  // point at original geometry?
            size += sizeof(bool);
            // float x,y,z
            size += sizeof(float) * 3 * vertexCount;

            return size;
      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcPoseKeyframeSize(const VertexPoseKeyFrame* kf)
      {
            size_t size = STREAM_OVERHEAD_SIZE;

            // float time
            size += sizeof(float);

            size += calcPoseKeyframePoseRefSize() * kf->getPoseReferences().size();

            return size;

      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcPoseKeyframePoseRefSize(void)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // unsigned short poseIndex
            size += sizeof(uint16);
            // float influence
            size += sizeof(float);

            return size;

      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcPosesSize(const Mesh* pMesh)
      {
            size_t size = STREAM_OVERHEAD_SIZE;

            Mesh::ConstPoseIterator poseIt = pMesh->getPoseIterator();
            while (poseIt.hasMoreElements())
            {
                  size += calcPoseSize(poseIt.getNext());
            }
            return size;
      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcPoseSize(const Pose* pose)
      {
            size_t size = STREAM_OVERHEAD_SIZE;

            // char* name (may be blank)
            size += pose->getName().length() + 1;
            // unsigned short target
            size += sizeof(uint16);

            // vertex offsets
            size += pose->getVertexOffsets().size() * calcPoseVertexSize();

            return size;

      }
      //---------------------------------------------------------------------
      size_t MeshSerializerImpl::calcPoseVertexSize(void)
      {
            size_t size = STREAM_OVERHEAD_SIZE;
            // unsigned long vertexIndex
            size += sizeof(uint32);
            // float xoffset, yoffset, zoffset
            size += sizeof(float) * 3;

            return size;
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writePoses(const Mesh* pMesh)
      {
            Mesh::ConstPoseIterator poseIterator = pMesh->getPoseIterator();
            if (poseIterator.hasMoreElements())
            {
                  writeChunkHeader(M_POSES, calcPosesSize(pMesh));
                  while (poseIterator.hasMoreElements())
                  {
                        writePose(poseIterator.getNext());
                  }
            }

      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writePose(const Pose* pose)
      {
            writeChunkHeader(M_POSE, calcPoseSize(pose));

            // char* name (may be blank)
            writeString(pose->getName());

            // unsigned short target
            ushort val = pose->getTarget();
            writeShorts(&val, 1);

            size_t vertexSize = calcPoseVertexSize();
            Pose::ConstVertexOffsetIterator vit = pose->getVertexOffsetIterator();
            while (vit.hasMoreElements())
            {
                  uint32 vertexIndex = (uint32)vit.peekNextKey();
                  Vector3 offset = vit.getNext();
                  writeChunkHeader(M_POSE_VERTEX, vertexSize);
                  // unsigned long vertexIndex
                  writeInts(&vertexIndex, 1);
                  // float xoffset, yoffset, zoffset
                  writeFloats(offset.ptr(), 3);
            }


      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writeAnimations(const Mesh* pMesh)
      {
            writeChunkHeader(M_ANIMATIONS, calcAnimationsSize(pMesh));

            for (unsigned short a = 0; a < pMesh->getNumAnimations(); ++a)
            {
                  Animation* anim = pMesh->getAnimation(a);
                  LogManager::getSingleton().logMessage("Exporting animation " + anim->getName());
                  writeAnimation(anim);
                  LogManager::getSingleton().logMessage("Animation exported.");
            }
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writeAnimation(const Animation* anim)
      {
            writeChunkHeader(M_ANIMATION, calcAnimationSize(anim));
            // char* name
            writeString(anim->getName());
            // float length
            float len = anim->getLength();
            writeFloats(&len, 1);
            Animation::VertexTrackIterator trackIt = anim->getVertexTrackIterator();
            while (trackIt.hasMoreElements())
            {
                  VertexAnimationTrack* vt = trackIt.getNext();
                  writeAnimationTrack(vt);
            }


      }
    //---------------------------------------------------------------------
      void MeshSerializerImpl::writeAnimationTrack(const VertexAnimationTrack* track)
      {
            writeChunkHeader(M_ANIMATION_TRACK, calcAnimationTrackSize(track));
            // unsigned short type              // 1 == morph, 2 == pose
            uint16 animType = (uint16)track->getAnimationType();
            writeShorts(&animType, 1);
            // unsigned short target
            uint16 target = track->getHandle();
            writeShorts(&target, 1);

            if (track->getAnimationType() == VAT_MORPH)
            {
                  for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
                  {
                        VertexMorphKeyFrame* kf = track->getVertexMorphKeyFrame(i);
                        writeMorphKeyframe(kf, track->getAssociatedVertexData()->vertexCount);
                  }
            }
            else // VAT_POSE
            {
                  for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i)
                  {
                        VertexPoseKeyFrame* kf = track->getVertexPoseKeyFrame(i);
                        writePoseKeyframe(kf);
                  }
            }

      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writeMorphKeyframe(const VertexMorphKeyFrame* kf, size_t vertexCount)
      {
            writeChunkHeader(M_ANIMATION_MORPH_KEYFRAME, calcMorphKeyframeSize(kf, vertexCount));
            // float time
            float timePos = kf->getTime();
            writeFloats(&timePos, 1);
            // float x,y,z                // repeat by number of vertices in original geometry
            float* pSrc = static_cast<float*>(
                  kf->getVertexBuffer()->lock(HardwareBuffer::HBL_READ_ONLY));
            writeFloats(pSrc, vertexCount * 3);
            kf->getVertexBuffer()->unlock();
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writePoseKeyframe(const VertexPoseKeyFrame* kf)
      {
            writeChunkHeader(M_ANIMATION_POSE_KEYFRAME, calcPoseKeyframeSize(kf));
            // float time
            float timePos = kf->getTime();
            writeFloats(&timePos, 1);

            // pose references
            VertexPoseKeyFrame::ConstPoseRefIterator poseRefIt =
                  kf->getPoseReferenceIterator();
            while (poseRefIt.hasMoreElements())
            {
                  writePoseKeyframePoseRef(poseRefIt.getNext());
            }



      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::writePoseKeyframePoseRef(
            const VertexPoseKeyFrame::PoseRef& poseRef)
      {
            writeChunkHeader(M_ANIMATION_POSE_REF, calcPoseKeyframePoseRefSize());
            // unsigned short poseIndex
            writeShorts(&(poseRef.poseIndex), 1);
            // float influence
            writeFloats(&(poseRef.influence), 1);
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readPoses(DataStreamPtr& stream, Mesh* pMesh)
      {
            unsigned short streamID;

            // Find all substreams
            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        (streamID == M_POSE))
                  {
                        switch(streamID)
                        {
                        case M_POSE:
                              readPose(stream, pMesh);
                              break;

                        }

                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readPose(DataStreamPtr& stream, Mesh* pMesh)
      {
            // char* name (may be blank)
            String name = readString(stream);
            // unsigned short target
            unsigned short target;
            readShorts(stream, &target, 1);

            Pose* pose = pMesh->createPose(target, name);

            // Find all substreams
            unsigned short streamID;
            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        (streamID == M_POSE_VERTEX))
                  {
                        switch(streamID)
                        {
                        case M_POSE_VERTEX:
                              // create vertex offset
                              uint32 vertIndex;
                              Vector3 offset;
                              // unsigned long vertexIndex
                              readInts(stream, &vertIndex, 1);
                              // float xoffset, yoffset, zoffset
                              readFloats(stream, offset.ptr(), 3);

                              pose->addVertex(vertIndex, offset);
                              break;

                        }

                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }

      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readAnimations(DataStreamPtr& stream, Mesh* pMesh)
      {
            unsigned short streamID;

            // Find all substreams
            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        (streamID == M_ANIMATION))
                  {
                        switch(streamID)
                        {
                        case M_ANIMATION:
                              readAnimation(stream, pMesh);
                              break;

                        }

                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }


      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readAnimation(DataStreamPtr& stream, Mesh* pMesh)
      {

            // char* name
            String name = readString(stream);
            // float length
            float len;
            readFloats(stream, &len, 1);

            Animation* anim = pMesh->createAnimation(name, len);

            // tracks
            unsigned short streamID;

            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        streamID == M_ANIMATION_TRACK)
                  {
                        switch(streamID)
                        {
                        case M_ANIMATION_TRACK:
                              readAnimationTrack(stream, anim, pMesh);
                              break;
                        };
                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }
      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readAnimationTrack(DataStreamPtr& stream,
            Animation* anim, Mesh* pMesh)
      {
            // ushort type
            uint16 inAnimType;
            readShorts(stream, &inAnimType, 1);
            VertexAnimationType animType = (VertexAnimationType)inAnimType;

            // unsigned short target
            uint16 target;
            readShorts(stream, &target, 1);

            VertexAnimationTrack* track = anim->createVertexTrack(target,
                  pMesh->getVertexDataByTrackHandle(target), animType);

            // keyframes
            unsigned short streamID;

            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        (streamID == M_ANIMATION_MORPH_KEYFRAME ||
                         streamID == M_ANIMATION_POSE_KEYFRAME))
                  {
                        switch(streamID)
                        {
                        case M_ANIMATION_MORPH_KEYFRAME:
                              readMorphKeyFrame(stream, track);
                              break;
                        case M_ANIMATION_POSE_KEYFRAME:
                              readPoseKeyFrame(stream, track);
                              break;
                        };
                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }

      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readMorphKeyFrame(DataStreamPtr& stream, VertexAnimationTrack* track)
      {
            // float time
            float timePos;
            readFloats(stream, &timePos, 1);

            VertexMorphKeyFrame* kf = track->createVertexMorphKeyFrame(timePos);

            // Create buffer, allow read and use shadow buffer
            size_t vertexCount = track->getAssociatedVertexData()->vertexCount;
            HardwareVertexBufferSharedPtr vbuf =
                  HardwareBufferManager::getSingleton().createVertexBuffer(
                        VertexElement::getTypeSize(VET_FLOAT3), vertexCount,
                        HardwareBuffer::HBU_STATIC, true);
            // float x,y,z                // repeat by number of vertices in original geometry
            float* pDst = static_cast<float*>(
                  vbuf->lock(HardwareBuffer::HBL_DISCARD));
            readFloats(stream, pDst, vertexCount * 3);
            vbuf->unlock();
            kf->setVertexBuffer(vbuf);

      }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readPoseKeyFrame(DataStreamPtr& stream, VertexAnimationTrack* track)
      {
            // float time
            float timePos;
            readFloats(stream, &timePos, 1);

            // Create keyframe
            VertexPoseKeyFrame* kf = track->createVertexPoseKeyFrame(timePos);

            unsigned short streamID;

            if (!stream->eof())
            {
                  streamID = readChunk(stream);
                  while(!stream->eof() &&
                        streamID == M_ANIMATION_POSE_REF)
                  {
                        switch(streamID)
                        {
                        case M_ANIMATION_POSE_REF:
                              uint16 poseIndex;
                              float influence;
                              // unsigned short poseIndex
                              readShorts(stream, &poseIndex, 1);
                              // float influence
                              readFloats(stream, &influence, 1);

                              kf->addPoseReference(poseIndex, influence);

                              break;
                        };
                        if (!stream->eof())
                        {
                              streamID = readChunk(stream);
                        }

                  }
                  if (!stream->eof())
                  {
                        // Backpedal back to start of stream
                        stream->skip(-STREAM_OVERHEAD_SIZE);
                  }
            }

      }
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_3::MeshSerializerImpl_v1_3()
    {
        // Version number
        mVersion = "[MeshSerializer_v1.30]";
    }
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_3::~MeshSerializerImpl_v1_3()
    {
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_3::readEdgeListLodInfo(DataStreamPtr& stream,
        EdgeData* edgeData)
    {
        // unsigned long numTriangles
        uint32 numTriangles;
        readInts(stream, &numTriangles, 1);
        // Allocate correct amount of memory
        edgeData->triangles.resize(numTriangles);
        edgeData->triangleFaceNormals.resize(numTriangles);
        edgeData->triangleLightFacings.resize(numTriangles);
        // unsigned long numEdgeGroups
        uint32 numEdgeGroups;
        readInts(stream, &numEdgeGroups, 1);
        // Allocate correct amount of memory
        edgeData->edgeGroups.resize(numEdgeGroups);
        // Triangle* triangleList
        uint32 tmp[3];
        for (size_t t = 0; t < numTriangles; ++t)
        {
            EdgeData::Triangle& tri = edgeData->triangles[t];
            // unsigned long indexSet
            readInts(stream, tmp, 1);
            tri.indexSet = tmp[0];
            // unsigned long vertexSet
            readInts(stream, tmp, 1);
            tri.vertexSet = tmp[0];
            // unsigned long vertIndex[3]
            readInts(stream, tmp, 3);
            tri.vertIndex[0] = tmp[0];
            tri.vertIndex[1] = tmp[1];
            tri.vertIndex[2] = tmp[2];
            // unsigned long sharedVertIndex[3]
            readInts(stream, tmp, 3);
            tri.sharedVertIndex[0] = tmp[0];
            tri.sharedVertIndex[1] = tmp[1];
            tri.sharedVertIndex[2] = tmp[2];
            // float normal[4]
            readFloats(stream, &(edgeData->triangleFaceNormals[t].x), 4);

        }

        // Assume the mesh is closed, it will update later
        edgeData->isClosed = true;

        for (uint32 eg = 0; eg < numEdgeGroups; ++eg)
        {
            unsigned short streamID = readChunk(stream);
            if (streamID != M_EDGE_GROUP)
            {
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                    "Missing M_EDGE_GROUP stream",
                    "MeshSerializerImpl_v1_3::readEdgeListLodInfo");
            }
            EdgeData::EdgeGroup& edgeGroup = edgeData->edgeGroups[eg];

            // unsigned long vertexSet
            readInts(stream, tmp, 1);
            edgeGroup.vertexSet = tmp[0];
            // unsigned long numEdges
            uint32 numEdges;
            readInts(stream, &numEdges, 1);
            edgeGroup.edges.resize(numEdges);
            // Edge* edgeList
            for (uint32 e = 0; e < numEdges; ++e)
            {
                EdgeData::Edge& edge = edgeGroup.edges[e];
                // unsigned long  triIndex[2]
                readInts(stream, tmp, 2);
                edge.triIndex[0] = tmp[0];
                edge.triIndex[1] = tmp[1];
                // unsigned long  vertIndex[2]
                readInts(stream, tmp, 2);
                edge.vertIndex[0] = tmp[0];
                edge.vertIndex[1] = tmp[1];
                // unsigned long  sharedVertIndex[2]
                readInts(stream, tmp, 2);
                edge.sharedVertIndex[0] = tmp[0];
                edge.sharedVertIndex[1] = tmp[1];
                // bool degenerate
                readBools(stream, &(edge.degenerate), 1);

                // The mesh is closed only if no degenerate edge here
                if (edge.degenerate)
                {
                    edgeData->isClosed = false;
                }
            }
        }

        reorganiseTriangles(edgeData);
    }
    //---------------------------------------------------------------------
02545     void MeshSerializerImpl_v1_3::reorganiseTriangles(EdgeData* edgeData)
    {
        size_t numTriangles = edgeData->triangles.size();

        if (edgeData->edgeGroups.size() == 1)
        {
            // Special case for only one edge group in the edge list, which occuring
            // most time. In this case, all triangles belongs to that group.
            edgeData->edgeGroups.front().triStart = 0;
            edgeData->edgeGroups.front().triCount = numTriangles;
        }
        else
        {
            EdgeData::EdgeGroupList::iterator egi, egend;
            egend = edgeData->edgeGroups.end();

            // Calculate number of triangles for edge groups

            for (egi = edgeData->edgeGroups.begin(); egi != egend; ++egi)
            {
                egi->triStart = 0;
                egi->triCount = 0;
            }

            bool isGrouped = true;
            EdgeData::EdgeGroup* lastEdgeGroup = 0;
            for (size_t t = 0; t < numTriangles; ++t)
            {
                // Gets the edge group that the triangle belongs to
                const EdgeData::Triangle& tri = edgeData->triangles[t];
                EdgeData::EdgeGroup* edgeGroup = &edgeData->edgeGroups[tri.vertexSet];

                // Does edge group changes from last edge group?
                if (isGrouped && edgeGroup != lastEdgeGroup)
                {
                    // Remember last edge group
                    lastEdgeGroup = edgeGroup;

                    // Is't first time encounter this edge group?
                    if (!edgeGroup->triCount && !edgeGroup->triStart)
                    {
                        // setup first triangle of this edge group
                        edgeGroup->triStart = t;
                    }
                    else
                    {
                        // original triangles doesn't grouping by edge group
                        isGrouped = false;
                    }
                }

                // Count number of triangles for this edge group
                ++edgeGroup->triCount;
            }

            //
            // Note that triangles has been sorted by vertex set for a long time,
            // but never stored to old version mesh file.
            //
            // Adopt this fact to avoid remap triangles here.
            //

            // Does triangles grouped by vertex set?
            if (!isGrouped)
            {
                // Ok, the triangles of this edge list isn't grouped by vertex set
                // perfectly, seems ancient mesh file.
                //
                // We need work hardly to group triangles by vertex set.
                //

                // Calculate triStart and reset triCount to zero for each edge group first
                size_t triStart = 0;
                for (egi = edgeData->edgeGroups.begin(); egi != egend; ++egi)
                {
                    egi->triStart = triStart;
                    triStart += egi->triCount;
                    egi->triCount = 0;
                }

                // The map used to mapping original triangle index to new index
                typedef std::vector<size_t> TriangleIndexRemap;
                TriangleIndexRemap triangleIndexRemap(numTriangles);

                // New triangles information that should be group by vertex set.
                EdgeData::TriangleList newTriangles(numTriangles);
                EdgeData::TriangleFaceNormalList newTriangleFaceNormals(numTriangles);

                // Calculate triangle index map and organise triangles information
                for (size_t t = 0; t < numTriangles; ++t)
                {
                    // Gets the edge group that the triangle belongs to
                    const EdgeData::Triangle& tri = edgeData->triangles[t];
                    EdgeData::EdgeGroup& edgeGroup = edgeData->edgeGroups[tri.vertexSet];

                    // Calculate new index
                    size_t newIndex = edgeGroup.triStart + edgeGroup.triCount;
                    ++edgeGroup.triCount;

                    // Setup triangle index mapping entry
                    triangleIndexRemap[t] = newIndex;

                    // Copy triangle info to new placement
                    newTriangles[newIndex] = tri;
                    newTriangleFaceNormals[newIndex] = edgeData->triangleFaceNormals[t];
                }

                // Replace with new triangles information
                edgeData->triangles.swap(newTriangles);
                edgeData->triangleFaceNormals.swap(newTriangleFaceNormals);

                // Now, update old triangle indices to new index
                for (egi = edgeData->edgeGroups.begin(); egi != egend; ++egi)
                {
                    EdgeData::EdgeList::iterator ei, eend;
                    eend = egi->edges.end();
                    for (ei = egi->edges.begin(); ei != eend; ++ei)
                    {
                        ei->triIndex[0] = triangleIndexRemap[ei->triIndex[0]];
                        if (!ei->degenerate)
                        {
                            ei->triIndex[1] = triangleIndexRemap[ei->triIndex[1]];
                        }
                    }
                }
            }
        }
    }
      //---------------------------------------------------------------------
      void MeshSerializerImpl::readExtremes(DataStreamPtr& stream, Mesh *pMesh)
      {
            unsigned short idx;
            readShorts(stream, &idx, 1);

            SubMesh *sm = pMesh->getSubMesh (idx);

            int n_floats = (mCurrentstreamLen - STREAM_OVERHEAD_SIZE -
                                    sizeof (unsigned short)) / sizeof (float);

        assert ((n_floats % 3) == 0);

        float *vert = new float[n_floats];
            readFloats(stream, vert, n_floats);

        for (int i = 0; i < n_floats; i += 3)
                  sm->extremityPoints.push_back(Vector3(vert [i], vert [i + 1], vert [i + 2]));

        delete [] vert;
      }
      //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_2::MeshSerializerImpl_v1_2()
    {
        // Version number
        mVersion = "[MeshSerializer_v1.20]";
    }
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_2::~MeshSerializerImpl_v1_2()
    {
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readMesh(DataStreamPtr& stream, Mesh* pMesh)
    {
        MeshSerializerImpl::readMesh(stream, pMesh);
        // Always automatically build edge lists for this version
        pMesh->mAutoBuildEdgeLists = true;

    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readGeometry(DataStreamPtr& stream, Mesh* pMesh,
        VertexData* dest)
    {
        unsigned short texCoordSet = 0;

        unsigned short bindIdx = 0;

        dest->vertexStart = 0;

        unsigned int vertexCount = 0;
        readInts(stream, &vertexCount, 1);
        dest->vertexCount = vertexCount;

        // Vertex buffers

        readGeometryPositions(bindIdx, stream, pMesh, dest);
        ++bindIdx;

        // Find optional geometry streams
        if (!stream->eof())
        {
            unsigned short streamID = readChunk(stream);
            while(!stream->eof() &&
                (streamID == M_GEOMETRY_NORMALS ||
                 streamID == M_GEOMETRY_COLOURS ||
                 streamID == M_GEOMETRY_TEXCOORDS ))
            {
                switch (streamID)
                {
                case M_GEOMETRY_NORMALS:
                    readGeometryNormals(bindIdx++, stream, pMesh, dest);
                    break;
                case M_GEOMETRY_COLOURS:
                    readGeometryColours(bindIdx++, stream, pMesh, dest);
                    break;
                case M_GEOMETRY_TEXCOORDS:
                    readGeometryTexCoords(bindIdx++, stream, pMesh, dest, texCoordSet++);
                    break;
                }
                // Get next stream
                if (!stream->eof())
                {
                    streamID = readChunk(stream);
                }
            }
            if (!stream->eof())
            {
                // Backpedal back to start of non-submesh stream
                stream->skip(-STREAM_OVERHEAD_SIZE);
            }
        }
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readGeometryPositions(unsigned short bindIdx,
        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
    {
        float *pFloat = 0;
        HardwareVertexBufferSharedPtr vbuf;
        // float* pVertices (x, y, z order x numVertices)
        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_POSITION);
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            dest->vertexDeclaration->getVertexSize(bindIdx),
            dest->vertexCount,
            pMesh->mVertexBufferUsage,
                  pMesh->mIndexBufferShadowBuffer);
        pFloat = static_cast<float*>(
            vbuf->lock(HardwareBuffer::HBL_DISCARD));
        readFloats(stream, pFloat, dest->vertexCount * 3);
        vbuf->unlock();
        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readGeometryNormals(unsigned short bindIdx,
        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
    {
        float *pFloat = 0;
        HardwareVertexBufferSharedPtr vbuf;
        // float* pNormals (x, y, z order x numVertices)
        dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_NORMAL);
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            dest->vertexDeclaration->getVertexSize(bindIdx),
            dest->vertexCount,
            pMesh->mVertexBufferUsage,
                  pMesh->mVertexBufferShadowBuffer);
        pFloat = static_cast<float*>(
            vbuf->lock(HardwareBuffer::HBL_DISCARD));
        readFloats(stream, pFloat, dest->vertexCount * 3);
        vbuf->unlock();
        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readGeometryColours(unsigned short bindIdx,
        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest)
    {
        RGBA* pRGBA = 0;
        HardwareVertexBufferSharedPtr vbuf;
        // unsigned long* pColours (RGBA 8888 format x numVertices)
        dest->vertexDeclaration->addElement(bindIdx, 0, VET_COLOUR, VES_DIFFUSE);
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            dest->vertexDeclaration->getVertexSize(bindIdx),
            dest->vertexCount,
            pMesh->mVertexBufferUsage,
                  pMesh->mVertexBufferShadowBuffer);
        pRGBA = static_cast<RGBA*>(
            vbuf->lock(HardwareBuffer::HBL_DISCARD));
        readInts(stream, pRGBA, dest->vertexCount);
        vbuf->unlock();
        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_2::readGeometryTexCoords(unsigned short bindIdx,
        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
    {
        float *pFloat = 0;
        HardwareVertexBufferSharedPtr vbuf;
        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
        unsigned short dim;
        readShorts(stream, &dim, 1);
        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
        dest->vertexDeclaration->addElement(
            bindIdx,
            0,
            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
            VES_TEXTURE_COORDINATES,
            texCoordSet);
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            dest->vertexDeclaration->getVertexSize(bindIdx),
            dest->vertexCount,
            pMesh->mVertexBufferUsage,
                  pMesh->mVertexBufferShadowBuffer);
        pFloat = static_cast<float*>(
            vbuf->lock(HardwareBuffer::HBL_DISCARD));
        readFloats(stream, pFloat, dest->vertexCount * dim);
        vbuf->unlock();
        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
    }
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_1::MeshSerializerImpl_v1_1()
    {
        // Version number
        mVersion = "[MeshSerializer_v1.10]";
    }
    //---------------------------------------------------------------------
    MeshSerializerImpl_v1_1::~MeshSerializerImpl_v1_1()
    {
    }
    //---------------------------------------------------------------------
    void MeshSerializerImpl_v1_1::readGeometryTexCoords(unsigned short bindIdx,
        DataStreamPtr& stream, Mesh* pMesh, VertexData* dest, unsigned short texCoordSet)
    {
        float *pFloat = 0;
        HardwareVertexBufferSharedPtr vbuf;
        // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
        unsigned short dim;
        readShorts(stream, &dim, 1);
        // float* pTexCoords  (u [v] [w] order, dimensions x numVertices)
        dest->vertexDeclaration->addElement(
            bindIdx,
            0,
            VertexElement::multiplyTypeCount(VET_FLOAT1, dim),
            VES_TEXTURE_COORDINATES,
            texCoordSet);
        vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
            dest->vertexDeclaration->getVertexSize(bindIdx),
            dest->vertexCount,
            pMesh->getVertexBufferUsage(),
                  pMesh->isVertexBufferShadowed());
        pFloat = static_cast<float*>(
            vbuf->lock(HardwareBuffer::HBL_DISCARD));
        readFloats(stream, pFloat, dest->vertexCount * dim);

        // Adjust individual v values to (1 - v)
        if (dim == 2)
        {
            for (size_t i = 0; i < dest->vertexCount; ++i)
            {
                ++pFloat; // skip u
                *pFloat = 1.0 - *pFloat; // v = 1 - v
                ++pFloat;
            }

        }
        vbuf->unlock();
        dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
    }
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------
    //---------------------------------------------------------------------




}


Generated by  Doxygen 1.6.0   Back to index