//---------------------------------------------------------------------
std::vector<char> OgreMeshDeserializer::readGeometryVertexBuffer(unsigned int vertexCount)
{
    std::vector<char> vertices;
    unsigned short bindIndex, vertexSize;
    // unsigned short bindIndex;    // Index to bind this buffer to
    readShorts(m_stream, &bindIndex, 1);
    // unsigned short vertexSize;   // Per-vertex size, must agree with declaration at this index
    readShorts(m_stream, &vertexSize, 1);

    {
        // Check for vertex data header
        unsigned short headerID;
        headerID = readChunk(m_stream);
        if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA) {
            std::runtime_error("Can't find vertex buffer data area");
        }

        // Create / populate vertex buffer
        vertices.resize(vertexCount * vertexSize);
        m_stream.read(vertices.data(), vertexCount * vertexSize);

    }

    return vertices;
}
    //---------------------------------------------------------------------
    void
    BackgroundFileSerializer::readLayer( Ogre::DataStreamPtr &stream
                                        ,Layer *pDest, size_t layer_index )
    {
        if( !pDest->enabled ) return;

        uint16 tmp[4], sprite_count;
        readShorts( stream, tmp, 4 );
        pDest->width        = tmp[0];
        pDest->height       = tmp[1];
        sprite_count        = tmp[2];
        pDest->unknown_06   = tmp[3];

        switch( layer_index )
        {
          case 1:
            readShorts( stream, pDest->unknown_08, 3 );
          case 2:
          case 3:
            readShorts( stream, pDest->unknown_0E, 4 );
        }
        stream->skip( 2 * 2 ); // 2 * uint16 unused;
        m_layer_index = layer_index;
        readVector( stream, pDest->sprites, sprite_count );

        removeBuggySprites( pDest->sprites );
    }
//---------------------------------------------------------------------
OgreMeshDeserializer::VertexElement OgreMeshDeserializer::readGeometryVertexElement()
{
    VertexElement element{};
    // unsigned short source;   // buffer bind source
    readShorts(m_stream, &element.source, 1);
    // unsigned short type;     // VertexElementType
    readShorts(m_stream, &element.vType, 1);
    // unsigned short semantic; // VertexElementSemantic
    readShorts(m_stream, &element.vSemantic, 1);
    // unsigned short offset;   // start offset in buffer in bytes
    readShorts(m_stream, &element.offset, 1);
    // unsigned short index;    // index of the semantic
    readShorts(m_stream, &element.index, 1);
    return element;
}
    void StatefulMeshSerializer::determineFileFormat(DataStreamPtr stream)
    {
        determineEndianness(stream);

        // Read header and determine the version
        unsigned short headerID;
        
        // Read header ID
        readShorts(stream, &headerID, 1);
        
        if (headerID != HEADER_CHUNK_ID)
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "File header not found",
                "MeshSerializer::importMesh");
        }
        // Read version
        mMeshFileVersion = readString(stream);
        // Jump back to start
        stream->seek(0);

#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
        mMeshFileEndian = mFlipEndian ? ENDIAN_LITTLE : ENDIAN_BIG;
#else
        mMeshFileEndian = mFlipEndian ? ENDIAN_BIG : ENDIAN_LITTLE;
#endif
    }
	//---------------------------------------------------------------------
	void SkeletonSerializer::readFileHeader(DataStreamPtr& stream)
	{
		unsigned short headerID;

		// Read header ID
		readShorts(stream, &headerID, 1);

		if (headerID == HEADER_STREAM_ID_EXT)
		{
			// Read version
			String ver = readString(stream);
			if ((ver != "[Serializer_v1.10]") &&
				(ver != "[Serializer_v1.80]"))
			{
				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
					"Invalid file: version incompatible, file reports " + String(ver),
					"Serializer::readFileHeader");
			}
			mVersion = ver;
		}
		else
		{
			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid file: no header", 
				"Serializer::readFileHeader");
		}
	}
    //---------------------------------------------------------------------
    void SkeletonSerializer::readBone(DataStreamPtr& stream, Skeleton* pSkel)
    {
        // char* name
        String name = readString(stream);
        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
        unsigned short handle;
        readShorts(stream, &handle, 1);

        // Create new bone
        Bone* pBone = pSkel->createBone(name, handle);

        // Vector3 position                 : position of this bone relative to parent 
        Vector3 pos;
        readObject(stream, pos);
        pBone->setPosition(pos);
        // Quaternion orientation           : orientation of this bone relative to parent 
        Quaternion q;
        readObject(stream, q);
        pBone->setOrientation(q);

#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
        // Hack to fix chunk size validation:
        mChunkSizeStack.back() += calcStringSize(name);
#endif
        // TODO: don't depend on mCurrentstreamLen in next skeleton format!
        // Currently we use wrong chunk sizes, but we can't fix it, because we depend on mCurrentstreamLen
        // Do we have scale?
        if (mCurrentstreamLen > calcBoneSizeWithoutScale(pSkel, pBone))
        {
            Vector3 scale;
            readObject(stream, scale);
            pBone->setScale(scale);
        }
        
    }
Beispiel #7
0
    //---------------------------------------------------------------------
    void Serializer::readFileHeader(DataStreamPtr& stream)
    {
        unsigned short headerID;
        
        // Read header ID
        readShorts(stream, &headerID, 1);
        
        if (headerID == HEADER_STREAM_ID)
        {
            // Read version
            String ver = readString(stream);
            if (ver != mVersion)
            {
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
                    "Invalid file: version incompatible, file reports " + String(ver) +
                    " Serializer is version " + mVersion,
                    "Serializer::readFileHeader");
            }
        }
        else
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid file: no header", 
                "Serializer::readFileHeader");
        }

    }
    //---------------------------------------------------------------------
    void SkeletonSerializer::readBone(DataStreamPtr& stream, Skeleton* pSkel)
    {
        // char* name
        String name = readString(stream);
        // unsigned short handle            : handle of the bone, should be contiguous & start at 0
        unsigned short handle;
        readShorts(stream, &handle, 1);

        // Create new bone
        Bone* pBone = pSkel->createBone(name, handle);

        // Vector3 position                 : position of this bone relative to parent 
        Vector3 pos;
        readObject(stream, pos);
        pBone->setPosition(pos);
        // Quaternion orientation           : orientation of this bone relative to parent 
        Quaternion q;
        readObject(stream, q);
        pBone->setOrientation(q);
        // Do we have scale?
        if (mCurrentstreamLen > calcBoneSizeWithoutScale(pSkel, pBone))
        {
            Vector3 scale;
            readObject(stream, scale);
            pBone->setScale(scale);
        }
    }
Beispiel #9
0
	unsigned short Serializer::readChunk()
	{
		unsigned short id;
		readShorts(&id, 1);
		readInts(&mCurrentStreamLen, 1);
		return id;
	}
Beispiel #10
0
 //---------------------------------------------------------------------
 unsigned short Serializer::readChunk(DataStreamPtr& stream)
 {
     unsigned short id;
     readShorts(stream, &id, 1);
     
     readInts(stream, &mCurrentstreamLen, 1);
     return id;
 }
 //---------------------------------------------------------------------
 void
 BackgroundFileSerializer::readFileHeader( Ogre::DataStreamPtr &stream )
 {
     uint16 data[2];
     readShorts( stream, data, 2 );
     m_header.unused = data[0];
     m_header.sort_sprites_by_palette = data[1];
 }
 //----------------------------------------------------------------------
 void WalkmeshFileSerializer::readObject( Ogre::DataStreamPtr &stream
                                         ,WalkmeshFileSerializer::Access &pDest )
 {
     uint16 tmp[ ACCESS_COMPONENT_COUNT ];
     readShorts( stream, tmp, ACCESS_COMPONENT_COUNT );
     pDest.a = tmp[0];
     pDest.b = tmp[1];
     pDest.c = tmp[2];
 }
 //----------------------------------------------------------------------
 void WalkmeshFileSerializer::readObject( Ogre::DataStreamPtr &stream
                                         ,Ogre::Vector3 &pDest )
 {
     sint16 tmp[ VERTEX_COMPONENT_COUNT ];
     readShorts( stream, reinterpret_cast<uint16*>( tmp ), VERTEX_COMPONENT_COUNT );
     pDest.x = static_cast<Ogre::Real>( tmp[0] );
     pDest.y = static_cast<Ogre::Real>( tmp[1] );
     pDest.z = static_cast<Ogre::Real>( tmp[2] );
 }
//---------------------------------------------------------------------
unsigned short OgreMeshDeserializer::readChunk(std::istream& stream)
{
    unsigned short id;
    readShorts(stream, &id, 1);

    readInts(stream, &mCurrentstreamLen, 1);

    return id;
}
    //---------------------------------------------------------------------
    void SkeletonSerializer::readBoneParent(DataStreamPtr& stream, Skeleton* pSkel)
    {
        // All bones have been created by this point
        Bone *child, *parent;
        unsigned short childHandle, parentHandle;

        // unsigned short handle             : child bone
        readShorts(stream, &childHandle, 1);
        // unsigned short parentHandle   : parent bone
        readShorts(stream, &parentHandle, 1);

        // Find bones
        parent = pSkel->getBone(parentHandle);
        child = pSkel->getBone(childHandle);

        // attach
        parent->addChild(child);

    }
Beispiel #16
0
    //---------------------------------------------------------------------
    void MeshSerializer::importMesh(DataStreamPtr& stream, Mesh* pDest)
    {
        determineEndianness(stream);

        // Read header and determine the version
        unsigned short headerID;
        
        // Read header ID
        readShorts(stream, &headerID, 1);
        
        if (headerID != HEADER_CHUNK_ID)
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "File header not found",
                "MeshSerializer::importMesh");
        }
        // Read version
        String ver = readString(stream);
        // Jump back to start
        stream->seek(0);

        // Find the implementation to use
        MeshSerializerImpl* impl = 0;
        for (MeshVersionDataList::iterator i = mVersionData.begin(); 
             i != mVersionData.end(); ++i)
        {
            if ((*i)->versionString == ver)
            {
                impl = (*i)->impl;
                break;
            }
        }           
        if (!impl)
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot find serializer implementation for "
                        "mesh version " + ver, "MeshSerializer::importMesh");
        
        // Call implementation
        impl->importMesh(stream, pDest, mListener);
        // Warn on old version of mesh
        if (ver != mVersionData[0]->versionString)
        {
            LogManager::getSingleton().logMessage("WARNING: " + pDest->getName() + 
                " is an older format (" + ver + "); you should upgrade it as soon as possible" +
                " using the OgreMeshTool tool.", LML_CRITICAL);
        }

        if(mListener)
            mListener->processMeshCompleted(pDest);
    }
    //---------------------------------------------------------------------
    void SkeletonSerializer::importSkeleton(DataStreamPtr& stream, Skeleton* pSkel)
    {
        // Determine endianness (must be the first thing we do!)
        determineEndianness(stream);

        // Check header
        readFileHeader(stream);
        pushInnerChunk(stream);
        unsigned short streamID = readChunk(stream);

        while(!stream->eof())
        {
            switch (streamID)
            {
            case SKELETON_BLENDMODE:
            {
                // Optional blend mode
                uint16 blendMode;
                readShorts(stream, &blendMode, 1);
                pSkel->setBlendMode(static_cast<SkeletonAnimationBlendMode>(blendMode));
                break;
            }
            case SKELETON_BONE:
                readBone(stream, pSkel);
                break;
            case SKELETON_BONE_PARENT:
                readBoneParent(stream, pSkel);
                break;
            case SKELETON_ANIMATION:
                readAnimation(stream, pSkel);
                break;
            case SKELETON_ANIMATION_LINK:
                readSkeletonAnimationLink(stream, pSkel);
                break;
            default:
                break;
            }

            streamID = readChunk(stream);
        }
        // Assume bones are stored in the binding pose
        pSkel->setBindingPose();
        popInnerChunk(stream);

    }
	    //---------------------------------------------------------------------
	    void ParseOgre::importMesh(DataStreamPtr&	stream, OgreMesh* pDest)
	    {
	        determineEndianness(stream);
	
	        // Read header and determine the version
	        unsigned short headerID;//	=	*(U16*)p;
	        
	        // Read header ID
			//stream.g
	        readShorts(stream, &headerID, 1);
			//Read(&headerID,sizeof(headerID),1,pData,uiPos);
	        
	        if (headerID != HEADER_CHUNK_ID)
	        {
	//             OGRE_EXCEPT(0, "File header not found",
	//                 "ParseOgre::importMesh");
	        }
	        // Read version
	        AString ver = readString(stream);
	// 		AChar	version[MAX_NAME];
	// 		ReadStr(pData,version,uiPos);
	// 		ver	=	version;
	        // Jump back to start
	        stream->seek(0);
	
	        // Find the implementation to use
	        ParseOgreImplMap::iterator impl = mImplementations.find(ver);
	        if (impl == mImplementations.end())
	        {
	//             OGRE_EXCEPT(0, "Cannot find serializer implementation for "
	//                 "current version " + ver, "ParseOgre::importMesh");
	        }
	
	        // Call implementation
	        impl->second->importMesh(stream, pDest, mListener);
	        // Warn on old version of mesh
	        if (ver != msCurrentVersion)
	        {
	//             LogManager("WARNING: " + pDest->getName() + 
	//                 " is an older format (" + ver + "); you should upgrade it as soon as possible" +
	//                 " using the OgreMeshUpgrade tool.");
	        }
	
	    }
//---------------------------------------------------------------------
void OgreMeshDeserializer::readFileHeader(std::istream& stream)
{
    unsigned short headerID;

    // Read header ID
    readShorts(stream, &headerID, 1);

    if (headerID == HEADER_STREAM_ID) {
        // Read version
        std::string ver = readString(stream);
        if (ver != OGRE_MESH_VERSION) {
            std::runtime_error("Invalid file: version incompatible, file reports " + ver +
                               " Deserializer is version " + OGRE_MESH_VERSION);
        }
    } else {
        std::runtime_error("Invalid file: no header");
    }

}
Beispiel #20
0
    //---------------------------------------------------------------------
    unsigned short Serializer::readChunk(DataStreamPtr& stream)
    {
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
        size_t pos = stream->tell();
#endif
        unsigned short id;
        readShorts(stream, &id, 1);
        
        readInts(stream, &mCurrentstreamLen, 1);
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
        if (!mChunkSizeStack.empty() && !stream->eof()){
            if (pos != static_cast<size_t>(mChunkSizeStack.back()) && mReportChunkErrors){
                LogManager::getSingleton().logMessage("Corrupted chunk detected! Stream name: '" + stream->getName() + "' Chunk id: " + StringConverter::toString(id));
            }
            mChunkSizeStack.back() = pos + mCurrentstreamLen;
        }
#endif
        return id;
    }
    //---------------------------------------------------------------------
    void MeshSerializer::importMesh(DataStreamPtr& stream, Mesh* pDest)
    {
        determineEndianness(stream);

        // Read header and determine the version
        unsigned short headerID;
        
        // Read header ID
        readShorts(stream, &headerID, 1);
        
        if (headerID != HEADER_CHUNK_ID)
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "File header not found",
                "MeshSerializer::importMesh");
        }
        // Read version
        String ver = readString(stream);
        // Jump back to start
        stream->seek(0);

        // Find the implementation to use
        MeshSerializerImplMap::iterator impl = mImplementations.find(ver);
        if (impl == mImplementations.end())
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot find serializer implementation for "
                "current version " + ver, "MeshSerializer::importMesh");
        }

        // Call implementation
        impl->second->importMesh(stream, pDest, mListener);
        // Warn on old version of mesh
        if (ver != msCurrentVersion)
        {
            LogManager::getSingleton().logMessage("WARNING: " + pDest->getName() + 
                " is an older format (" + ver + "); you should upgrade it as soon as possible" +
                " using the OgreMeshUpgrade tool.");
        }

    }
    //---------------------------------------------------------------------
    void SkeletonSerializer::readAnimationTrack(DataStreamPtr& stream, Animation* anim, 
        Skeleton* pSkel)
    {
        // unsigned short boneIndex     : Index of bone to apply to
        unsigned short boneHandle;
        readShorts(stream, &boneHandle, 1);

        // Find bone
        Bone *targetBone = pSkel->getBone(boneHandle);

        // Create track
        NodeAnimationTrack* pTrack = anim->createNodeTrack(boneHandle, targetBone);

        // Keep looking for nested keyframes
        if (!stream->eof())
        {
            pushInnerChunk(stream);
            unsigned short streamID = readChunk(stream);
            while(streamID == SKELETON_ANIMATION_TRACK_KEYFRAME && !stream->eof())
            {
                readKeyFrame(stream, pTrack, pSkel);

                if (!stream->eof())
                {
                    // Get next stream
                    streamID = readChunk(stream);
                }
            }
            if (!stream->eof())
            {
                // Backpedal back to start of this stream if we've found a non-keyframe
                backpedalChunkHeader(stream);
            }
            popInnerChunk(stream);
        }


    }
static spAttachment *readAttachment(spSkeletonBinary *self, spSkin *skin, int slotIndex, const char *attachmentName)
{
    spAttachment *attachment = NULL;
    float scale = self->scale;
    
    char *name = readString(self);
    if (name == NULL) name = (char *)attachmentName;
    
    switch ((spAttachmentType)readByte(self)) {
        case SP_ATTACHMENT_REGION: {
            spRegionAttachment *region;
            
            char *path = readString(self);
            if (path == NULL) path = name;
            
            attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, SP_ATTACHMENT_REGION, name, path);
            region = SUB_CAST(spRegionAttachment, attachment);
            if (path) {
                region->path = copyString(path);
            }
            
            region->rotation = readFloat(self);
            region->x = readFloat(self) * scale;
            region->y = readFloat(self) * scale;
            region->scaleX = readFloat(self);
            region->scaleY = readFloat(self);
            region->width = readFloat(self) * scale;
            region->height = readFloat(self) * scale;
            readColor(self, &region->r, &region->g, &region->b, &region->a);
            
            spRegionAttachment_updateOffset(region);
            spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
            break;
        }
        case SP_ATTACHMENT_BOUNDING_BOX: {
            spBoundingBoxAttachment *boundingBox;
            int vertexCount = readVarint(self, true);
            
            attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, SP_ATTACHMENT_BOUNDING_BOX, name, name);
            boundingBox = SUB_CAST(spBoundingBoxAttachment, attachment);
            readVertices(self, SUPER(boundingBox), vertexCount);
            SUPER(boundingBox)->worldVerticesLength = vertexCount << 1;
            
            spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
            
            break;
        }
        case SP_ATTACHMENT_MESH: {
            spMeshAttachment *mesh;
            int vertexCount;
            
            char *path = readString(self);
            if (path == NULL) path = name;
            
            attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, SP_ATTACHMENT_MESH, name, path);
            mesh = SUB_CAST(spMeshAttachment, attachment);
            if (path) {
                mesh->path = copyString(path);
            }
            
            readColor(self, &mesh->r, &mesh->g, &mesh->b, &mesh->a);
            vertexCount = readVarint(self, true);
            mesh->regionUVs = readFloats(self, 1, vertexCount << 1);
            mesh->trianglesCount = readVarint(self, true);
            mesh->triangles = readShorts(self, mesh->trianglesCount);
            readVertices(self, SUPER(mesh), vertexCount);
            SUPER(mesh)->worldVerticesLength = vertexCount << 1;
            mesh->hullLength = readVarint(self, true) << 1;
            
            spMeshAttachment_updateUVs(mesh);
            spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
            break;
        }
        case SP_ATTACHMENT_LINKED_MESH: {
            spMeshAttachment *mesh;
            
            char *parent;
            char *skinName;
            char *path = readString(self);
            if (path == NULL) path = name;
            
            attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, SP_ATTACHMENT_LINKED_MESH, name, path);
            mesh = SUB_CAST(spMeshAttachment, attachment);
            if (path) {
                mesh->path = copyString(path);
            }
            
            readColor(self, &mesh->r, &mesh->g, &mesh->b, &mesh->a);
            skinName = readString(self);
            parent = readString(self);
            mesh->inheritDeform = readBoolean(self);
            
            addLinkedMesh(self, mesh, skinName, slotIndex, parent);
            break;
        }
        case SP_ATTACHMENT_PATH: {
            spPathAttachment *path;
            int vertexCount;
            
            attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, SP_ATTACHMENT_PATH, name, NULL);
            path = SUB_CAST(spPathAttachment, attachment);
            
            path->closed = readBoolean(self);
            path->constantSpeed = readBoolean(self);
            vertexCount = readVarint(self, true);
            readVertices(self, SUPER(path), vertexCount);
            SUPER(path)->worldVerticesLength = vertexCount << 1;
            path->lengthsLength = vertexCount / 3;
            path->lengths = MALLOC(float, path->lengthsLength);
            for (int i = 0; i < path->lengthsLength; i++) {
                path->lengths[i] = readFloat(self) * self->scale;
            }
            
            break;
        }
    }
    
    return attachment;
}
    //---------------------------------------------------------------------
    void
    BackgroundFileSerializer::readObject( Ogre::DataStreamPtr &stream, SpriteData &pDest )
    {
        readObject( stream, pDest.dst );
        readShorts( stream, pDest.unknown_04, 2 );
        readObject( stream, pDest.src );
        readObject( stream, pDest.src2 );
        readShort( stream, pDest.width );
        readShort( stream, pDest.height );

        uint16 size;
        // width and height are sometimes incorrect in the file
        if ( m_layer_index < 2 )
        {
            size = 16;
        }
        else if ( m_layer_index < BackgroundFile::LAYER_COUNT)
        {
            size = 32;
        }
        else
        {
            OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS
                ,"m_layer_index not set correctly"
                ,"BackgroundFileSerializer::readObject" );
        }
        pDest.width = pDest.height = size;

        readShort( stream, pDest.palette_page );
        readShort( stream, pDest.depth );

        // Force depth values
        switch ( m_layer_index )
        {
          case 0:
            pDest.depth = 4095;
            break;
          case 2:
            pDest.depth = 4096;
            break;
          case 3:
            pDest.depth = 0;
            break;
        }

        uint8 animation[2];
        stream->read( animation, sizeof( animation ) );
        pDest.animation_id = animation[0];
        pDest.animation_frame = animation[1];
        uint8 has_blending[2];
        stream->read( has_blending, sizeof( has_blending ) );
        pDest.has_blending[0] = has_blending[0] > 0;
        pDest.has_blending[1] = has_blending[1] > 0;

        readShort( stream, pDest.blending );
        readShort( stream, pDest.data_page );
        readShort( stream, pDest.data_page2 );
        // when data_page2 != 0, it must be used instead of data_page (not for the first layer)
        if ( m_layer_index > 0 && pDest.data_page2 )
        {
            pDest.src = pDest.src2;
            pDest.data_page = pDest.data_page2;
        }
        readShort( stream, pDest.colour_depth );
        readObject( stream, pDest.src_big );
        pDest.src_big /= src_big_SCALE;
        stream->skip( 2 * 2 ); // 2 * uint16 unused
    }
//---------------------------------------------------------------------
void OgreMeshDeserializer::readSubMesh()
{
    unsigned short streamID;

    std::string materialName = readString(m_stream);

    bool useSharedVertices;
    readBools(m_stream, &useSharedVertices, 1);

    size_t offset = 0;
    if (!useSharedVertices) {
        offset = m_vertices.size() / 3;
    }

    unsigned int indexCount = 0;
    readInts(m_stream, &indexCount, 1);

    bool idx32bit;
    readBools(m_stream, &idx32bit, 1);
    if (indexCount > 0) {
        if (idx32bit) {

            std::vector<std::uint32_t> indices;
            indices.resize(indexCount);
            readInts(m_stream, indices.data(), indexCount);

            for (auto& index : indices) {
                m_indices.emplace_back(index + offset);
            }

        } else // 16-bit
        {
            std::vector<std::uint16_t> indices;
            indices.resize(indexCount);
            readShorts(m_stream, indices.data(), indexCount);
            for (auto& index : indices) {
                m_indices.emplace_back(index + offset);
            }
        }
    }


    {
        // M_GEOMETRY m_stream (Optional: present only if useSharedVertices = false)
        if (!useSharedVertices) {
            streamID = readChunk(m_stream);
            if (streamID != M_GEOMETRY) {
                std::runtime_error("Missing geometry data in mesh file");
            }
            readGeometry();
        }


        // Find all bone assignments, submesh operation, and texture aliases (if present)
        if (!m_stream.eof()) {
            streamID = readChunk(m_stream);
            while (!m_stream.eof() &&
                   (streamID == M_SUBMESH_BONE_ASSIGNMENT ||
                    streamID == M_SUBMESH_OPERATION ||
                    streamID == M_SUBMESH_TEXTURE_ALIAS)) {
                skipChunk(m_stream);

                if (!m_stream.eof()) {
                    streamID = readChunk(m_stream);
                }

            }
            if (!m_stream.eof()) {
                // Backpedal back to start of m_stream
                backpedalChunkHeader(m_stream);
            }
        }
    }


}
void SkeletonSerializerEx::readAnimationTrack(
	Ogre::DataStreamPtr& stream, Ogre::Animation* anim, Ogre::Skeleton* pSkel)
{
	// unsigned short boneIndex     : Index of bone to apply to
	unsigned short boneHandle;
	readShorts(stream, &boneHandle, 1);

	// Find bone
	Ogre::Bone *targetBone = pSkel->getBone(boneHandle);

	// Create track
	Ogre::NodeAnimationTrack* pTrack = anim->createNodeTrack(boneHandle, targetBone);

	// Keep looking for nested keyframes
	if (!stream->eof())
	{
		unsigned short streamID = readChunk(stream);
		while((streamID == Ogre::SKELETON_ANIMATION_TRACK_KEYFRAME || streamID == 0x4120 )
				&& !stream->eof())
		{
			if (streamID == 0x4120)
			{			
				unsigned short len;
				unsigned short flags;
				readShorts(stream, &len, 1);
				readShorts(stream, &flags, 1);

				float time;
				for (int i = 0; i < len; i += 1)
				{
					readFloats(stream, &time, 1);
					Ogre::TransformKeyFrame *kf = pTrack->createNodeKeyFrame(time);

					Ogre::Quaternion rot = Ogre::Quaternion::IDENTITY;
					if (flags & 1)
					{
						readObject(stream, rot);
					}
					kf->setRotation(rot);

					Ogre::Vector3 trans = Ogre::Vector3::ZERO;
					if (flags & 2)
					{
						readObject(stream, trans);
					}
					kf->setTranslate(trans);

					// 为正确解析天龙八部模型的骨骼动画              
					Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE;
					if (flags & 4)
					{
						readObject(stream, scale);
					}
					kf->setScale(scale);
				}
			}
			else
				readKeyFrame(stream, pTrack, pSkel);

			if (!stream->eof())
			{
				// Get next stream
				streamID = readChunk(stream);
			}
		}
		if (!stream->eof())
		{
			// Backpedal back to start of this stream if we've found a non-keyframe
			stream->skip(-STREAM_OVERHEAD_SIZE);
		}
	}
}