Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/Tools/XMLConverter/src/OgreXMLMeshSerializer.cpp @ 52

Last change on this file since 52 was 6, checked in by anonymous, 17 years ago

=…

File size: 67.0 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30
31#include "OgreXMLMeshSerializer.h"
32#include "OgreSubMesh.h"
33#include "OgreLogManager.h"
34#include "OgreSkeleton.h"
35#include "OgreStringConverter.h"
36#include "OgreHardwareBufferManager.h"
37#include "OgreException.h"
38#include "OgreAnimation.h"
39#include "OgreAnimationTrack.h"
40#include "OgreKeyFrame.h"
41
42namespace Ogre {
43
44    //---------------------------------------------------------------------
45    XMLMeshSerializer::XMLMeshSerializer()
46    {
47    }
48    //---------------------------------------------------------------------
49    XMLMeshSerializer::~XMLMeshSerializer()
50    {
51    }
52    //---------------------------------------------------------------------
53    void XMLMeshSerializer::importMesh(const String& filename, 
54                VertexElementType colourElementType, Mesh* pMesh)
55    {
56        LogManager::getSingleton().logMessage("XMLMeshSerializer reading mesh data from " + filename + "...");
57        mpMesh = pMesh;
58                mColourElementType = colourElementType;
59        mXMLDoc = new TiXmlDocument(filename);
60        mXMLDoc->LoadFile();
61
62        TiXmlElement* elem;
63
64        TiXmlElement* rootElem = mXMLDoc->RootElement();
65
66        // shared geometry
67        elem = rootElem->FirstChildElement("sharedgeometry");
68        if (elem)
69        {
70            const char *claimedVertexCount_ = elem->Attribute("vertexcount");
71            if(!claimedVertexCount_ || StringConverter::parseInt(claimedVertexCount_) > 0)
72            {
73                mpMesh->sharedVertexData = new VertexData();
74                readGeometry(elem, mpMesh->sharedVertexData);
75            }
76        }
77
78        // submeshes
79        elem = rootElem->FirstChildElement("submeshes");
80        if (elem)
81            readSubMeshes(elem);
82
83        // skeleton link
84        elem = rootElem->FirstChildElement("skeletonlink");
85        if (elem)
86            readSkeletonLink(elem);
87
88        // bone assignments
89        elem = rootElem->FirstChildElement("boneassignments");
90        if (elem)
91            readBoneAssignments(elem);
92
93                //Lod
94                elem = rootElem->FirstChildElement("levelofdetail");
95                if (elem)
96                        readLodInfo(elem);
97
98                // submesh names
99                elem = rootElem->FirstChildElement("submeshnames");
100                if (elem)
101                        readSubMeshNames(elem, mpMesh);
102
103                // submesh extremes
104                elem = rootElem->FirstChildElement("extremes");
105                if (elem)
106                        readExtremes(elem, mpMesh);
107
108                // poses
109                elem = rootElem->FirstChildElement("poses");
110                if (elem)
111                        readPoses(elem, mpMesh);
112
113                // animations
114                elem = rootElem->FirstChildElement("animations");
115                if (elem)
116                        readAnimations(elem, mpMesh);
117
118                delete mXMLDoc;
119
120        LogManager::getSingleton().logMessage("XMLMeshSerializer import successful.");
121       
122    }
123    //---------------------------------------------------------------------
124    void XMLMeshSerializer::exportMesh(const Mesh* pMesh, const String& filename)
125    {
126        LogManager::getSingleton().logMessage("XMLMeshSerializer writing mesh data to " + filename + "...");
127       
128        mpMesh = const_cast<Mesh*>(pMesh);
129
130        mXMLDoc = new TiXmlDocument();
131        mXMLDoc->InsertEndChild(TiXmlElement("mesh"));
132
133        LogManager::getSingleton().logMessage("Populating DOM...");
134
135           
136           
137        // Write to DOM
138        writeMesh(pMesh);
139        LogManager::getSingleton().logMessage("DOM populated, writing XML file..");
140
141        // Write out to a file
142        mXMLDoc->SaveFile(filename);
143
144   
145        delete mXMLDoc;
146
147        LogManager::getSingleton().logMessage("XMLMeshSerializer export successful.");
148
149    }
150    //---------------------------------------------------------------------
151    void XMLMeshSerializer::writeMesh(const Mesh* pMesh)
152    {
153        TiXmlElement* rootNode = mXMLDoc->RootElement();
154        // Write geometry
155                if (pMesh->sharedVertexData)
156                {
157                        TiXmlElement* geomNode = 
158                                rootNode->InsertEndChild(TiXmlElement("sharedgeometry"))->ToElement();
159                        writeGeometry(geomNode, pMesh->sharedVertexData);
160                }
161
162        // Write Submeshes
163        TiXmlElement* subMeshesNode = 
164            rootNode->InsertEndChild(TiXmlElement("submeshes"))->ToElement();
165        for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
166        {
167            LogManager::getSingleton().logMessage("Writing submesh...");
168            writeSubMesh(subMeshesNode, pMesh->getSubMesh(i));
169            LogManager::getSingleton().logMessage("Submesh exported.");
170        }
171
172        // Write skeleton info if required
173        if (pMesh->hasSkeleton())
174        {
175            LogManager::getSingleton().logMessage("Exporting skeleton link...");
176            // Write skeleton link
177            writeSkeletonLink(rootNode, pMesh->getSkeletonName());
178            LogManager::getSingleton().logMessage("Skeleton link exported.");
179
180            // Write bone assignments
181            Mesh::BoneAssignmentIterator bi = const_cast<Mesh*>(pMesh)->getBoneAssignmentIterator();
182            if (bi.hasMoreElements())
183            {
184                LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");
185                TiXmlElement* boneAssignNode = 
186                    rootNode->InsertEndChild(TiXmlElement("boneassignments"))->ToElement();
187
188                while (bi.hasMoreElements())
189                {
190                                        const VertexBoneAssignment& assign = bi.getNext();
191                    writeBoneAssignment(boneAssignNode, &assign);
192                }
193
194                LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
195            }
196        }
197                if (pMesh->getNumLodLevels() > 1)
198                {
199            LogManager::getSingleton().logMessage("Exporting LOD information...");
200                        writeLodInfo(rootNode, pMesh);
201            LogManager::getSingleton().logMessage("LOD information exported.");
202                }
203        // Write submesh names
204        writeSubMeshNames(rootNode, pMesh);
205                // Write poses
206                writePoses(rootNode, pMesh);
207                // Write animations
208                writeAnimations(rootNode, pMesh);
209        // Write extremes
210        writeExtremes(rootNode, pMesh);
211    }
212    //---------------------------------------------------------------------
213    void XMLMeshSerializer::writeSubMesh(TiXmlElement* mSubMeshesNode, const SubMesh* s)
214    {
215        TiXmlElement* subMeshNode = 
216            mSubMeshesNode->InsertEndChild(TiXmlElement("submesh"))->ToElement();
217
218        size_t numFaces;
219
220        // Material name
221        subMeshNode->SetAttribute("material", s->getMaterialName());
222        // bool useSharedVertices
223        subMeshNode->SetAttribute("usesharedvertices", 
224            StringConverter::toString(s->useSharedVertices) );
225        // bool use32BitIndexes
226                bool use32BitIndexes = (s->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
227        subMeshNode->SetAttribute("use32bitindexes", 
228            StringConverter::toString( use32BitIndexes ));
229
230        // Operation type
231        switch(s->operationType)
232        {
233        case RenderOperation::OT_LINE_LIST:
234        case RenderOperation::OT_LINE_STRIP:
235        case RenderOperation::OT_POINT_LIST:
236            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Unsupported operation type, only "
237                "triangle types are allowed.", "XMLMeshSerializer::writeSubMesh");
238            break;
239        case RenderOperation::OT_TRIANGLE_FAN:
240            subMeshNode->SetAttribute("operationtype", "triangle_fan");
241            break;
242        case RenderOperation::OT_TRIANGLE_LIST:
243            subMeshNode->SetAttribute("operationtype", "triangle_list");
244            break;
245        case RenderOperation::OT_TRIANGLE_STRIP:
246            subMeshNode->SetAttribute("operationtype", "triangle_strip");
247            break;
248        }
249
250        // Faces
251        TiXmlElement* facesNode = 
252            subMeshNode->InsertEndChild(TiXmlElement("faces"))->ToElement();
253        if (s->operationType == RenderOperation::OT_TRIANGLE_LIST)
254        {
255            // tri list
256            numFaces = s->indexData->indexCount / 3;
257        }
258        else
259        {
260            // triangle fan or triangle strip
261            numFaces = s->indexData->indexCount - 2;
262        }
263        facesNode->SetAttribute("count", 
264            StringConverter::toString(numFaces));
265        // Write each face in turn
266        size_t i;
267                unsigned int* pInt;
268                unsigned short* pShort;
269                HardwareIndexBufferSharedPtr ibuf = s->indexData->indexBuffer;
270                if (use32BitIndexes)
271                {
272                        pInt = static_cast<unsigned int*>(
273                                ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); 
274                }
275                else
276                {
277                        pShort = static_cast<unsigned short*>(
278                                ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); 
279                }
280        for (i = 0; i < numFaces; ++i)
281        {
282            TiXmlElement* faceNode = 
283                facesNode->InsertEndChild(TiXmlElement("face"))->ToElement();
284                        if (use32BitIndexes)
285                        {
286                                faceNode->SetAttribute("v1", StringConverter::toString(*pInt++));
287                /// Only need all 3 vertex indices if trilist or first face
288                if (s->operationType == RenderOperation::OT_TRIANGLE_LIST || i == 0)
289                {
290                                    faceNode->SetAttribute("v2", StringConverter::toString(*pInt++));
291                                    faceNode->SetAttribute("v3", StringConverter::toString(*pInt++));
292                }
293                        }
294                        else
295                        {
296                                faceNode->SetAttribute("v1", StringConverter::toString(*pShort++));
297                /// Only need all 3 vertex indices if trilist or first face
298                if (s->operationType == RenderOperation::OT_TRIANGLE_LIST || i == 0)
299                {
300                                    faceNode->SetAttribute("v2", StringConverter::toString(*pShort++));
301                                    faceNode->SetAttribute("v3", StringConverter::toString(*pShort++));
302                }
303                        }
304        }
305
306        // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
307        if (!s->useSharedVertices)
308        {
309            TiXmlElement* geomNode = 
310                subMeshNode->InsertEndChild(TiXmlElement("geometry"))->ToElement();
311            writeGeometry(geomNode, s->vertexData);
312        }
313
314        // texture aliases
315        writeTextureAliases(subMeshNode, s);
316
317        // Bone assignments
318        if (mpMesh->hasSkeleton())
319        {
320            SubMesh::BoneAssignmentIterator bi = const_cast<SubMesh*>(s)->getBoneAssignmentIterator();
321            LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");
322
323            TiXmlElement* boneAssignNode = 
324                subMeshNode->InsertEndChild(TiXmlElement("boneassignments"))->ToElement();
325            while (bi.hasMoreElements())
326            {
327                                const VertexBoneAssignment& assign = bi.getNext();
328                writeBoneAssignment(boneAssignNode, &assign);
329            }
330        }
331        LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
332
333    }
334    //---------------------------------------------------------------------
335    void XMLMeshSerializer::writeGeometry(TiXmlElement* mParentNode, const VertexData* vertexData)
336    {
337        // Write a vertex buffer per element
338
339        TiXmlElement *vbNode, *vertexNode, *dataNode;
340
341        // Set num verts on parent
342        mParentNode->SetAttribute("vertexcount", StringConverter::toString(vertexData->vertexCount));
343
344                VertexDeclaration* decl = vertexData->vertexDeclaration;
345                VertexBufferBinding* bind = vertexData->vertexBufferBinding;
346
347                VertexBufferBinding::VertexBufferBindingMap::const_iterator b, bend;
348                bend = bind->getBindings().end();
349                // Iterate over buffers
350                for(b = bind->getBindings().begin(); b != bend; ++b)
351                {
352                        vbNode = mParentNode->InsertEndChild(TiXmlElement("vertexbuffer"))->ToElement();
353                        const HardwareVertexBufferSharedPtr vbuf = b->second;
354                        unsigned short bufferIdx = b->first;
355                        // Get all the elements that relate to this buffer                     
356                        VertexDeclaration::VertexElementList elems = decl->findElementsBySource(bufferIdx);
357                        VertexDeclaration::VertexElementList::iterator i, iend;
358                        iend = elems.end();
359
360                        // Set up the data access for this buffer (lock read-only)
361                        unsigned char* pVert;
362                        float* pFloat;
363                        ARGB* pColour;
364
365                        pVert = static_cast<unsigned char*>(
366                                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
367
368            // Skim over the elements to set up the general data
369            unsigned short numTextureCoords = 0;
370                        for (i = elems.begin(); i != iend; ++i)
371                        {
372                                VertexElement& elem = *i;
373                                switch(elem.getSemantic())
374                                {
375                                case VES_POSITION:
376                                        vbNode->SetAttribute("positions","true");
377                    break;
378                                case VES_NORMAL:
379                                        vbNode->SetAttribute("normals","true");
380                    break;
381                                case VES_TANGENT:
382                                        vbNode->SetAttribute("tangents","true");
383                                        break;
384                                case VES_BINORMAL:
385                                        vbNode->SetAttribute("binormals","true");
386                                        break;
387                                case VES_DIFFUSE:
388                                        vbNode->SetAttribute("colours_diffuse","true");
389                    break;
390                                case VES_SPECULAR:
391                                        vbNode->SetAttribute("colours_specular","true");
392                    break;
393                case VES_TEXTURE_COORDINATES:
394                    vbNode->SetAttribute(
395                        "texture_coord_dimensions_" + StringConverter::toString(numTextureCoords), 
396                        StringConverter::toString(VertexElement::getTypeCount(elem.getType())));
397                    ++numTextureCoords;
398                    break;
399
400                default:
401                    break;
402                }
403            }
404            if (numTextureCoords > 0)
405            {
406                vbNode->SetAttribute("texture_coords", 
407                    StringConverter::toString(numTextureCoords));
408            }
409
410                        // For each vertex
411                        for (size_t v = 0; v < vertexData->vertexCount; ++v)
412                        {
413                vertexNode = 
414                    vbNode->InsertEndChild(TiXmlElement("vertex"))->ToElement();
415                                // Iterate over the elements
416                                for (i = elems.begin(); i != iend; ++i)
417                                {
418                                        VertexElement& elem = *i;
419                                        switch(elem.getSemantic())
420                                        {
421                                        case VES_POSITION:
422                                                elem.baseVertexPointerToElement(pVert, &pFloat);
423                                                dataNode = 
424                                                        vertexNode->InsertEndChild(TiXmlElement("position"))->ToElement();
425                                                dataNode->SetAttribute("x", StringConverter::toString(pFloat[0]));
426                                                dataNode->SetAttribute("y", StringConverter::toString(pFloat[1]));
427                                                dataNode->SetAttribute("z", StringConverter::toString(pFloat[2]));
428                                                break;
429                                        case VES_NORMAL:
430                                                elem.baseVertexPointerToElement(pVert, &pFloat);
431                                                dataNode = 
432                                                        vertexNode->InsertEndChild(TiXmlElement("normal"))->ToElement();
433                                                dataNode->SetAttribute("x", StringConverter::toString(pFloat[0]));
434                                                dataNode->SetAttribute("y", StringConverter::toString(pFloat[1]));
435                                                dataNode->SetAttribute("z", StringConverter::toString(pFloat[2]));
436                                                break;
437                                        case VES_TANGENT:
438                                                elem.baseVertexPointerToElement(pVert, &pFloat);
439                                                dataNode = 
440                                                        vertexNode->InsertEndChild(TiXmlElement("tangent"))->ToElement();
441                                                dataNode->SetAttribute("x", StringConverter::toString(pFloat[0]));
442                                                dataNode->SetAttribute("y", StringConverter::toString(pFloat[1]));
443                                                dataNode->SetAttribute("z", StringConverter::toString(pFloat[2]));
444                                                break;
445                                        case VES_BINORMAL:
446                                                elem.baseVertexPointerToElement(pVert, &pFloat);
447                                                dataNode = 
448                                                        vertexNode->InsertEndChild(TiXmlElement("binormal"))->ToElement();
449                                                dataNode->SetAttribute("x", StringConverter::toString(pFloat[0]));
450                                                dataNode->SetAttribute("y", StringConverter::toString(pFloat[1]));
451                                                dataNode->SetAttribute("z", StringConverter::toString(pFloat[2]));
452                                                break;
453                                        case VES_DIFFUSE:
454                                                elem.baseVertexPointerToElement(pVert, &pColour);
455                                                dataNode = 
456                                                        vertexNode->InsertEndChild(TiXmlElement("colour_diffuse"))->ToElement();
457                                                {
458                                                        ARGB rc = *pColour++;
459                                                        ColourValue cv;
460                                                        cv.b = (rc & 0xFF) / 255.0f;            rc >>= 8;
461                                                        cv.g = (rc & 0xFF) / 255.0f;            rc >>= 8;
462                                                        cv.r = (rc & 0xFF) / 255.0f;            rc >>= 8;
463                                                        cv.a = (rc & 0xFF) / 255.0f;
464                            dataNode->SetAttribute("value", StringConverter::toString(cv));
465                                                }
466                                                break;
467                                        case VES_SPECULAR:
468                                                elem.baseVertexPointerToElement(pVert, &pColour);
469                                                dataNode = 
470                                                        vertexNode->InsertEndChild(TiXmlElement("colour_specular"))->ToElement();
471                                                {
472                                                        ARGB rc = *pColour++;
473                                                        ColourValue cv;
474                                                        cv.b = (rc & 0xFF) / 255.0f;            rc >>= 8;
475                                                        cv.g = (rc & 0xFF) / 255.0f;            rc >>= 8;
476                                                        cv.r = (rc & 0xFF) / 255.0f;            rc >>= 8;
477                                                        cv.a = (rc & 0xFF) / 255.0f;
478                                                        dataNode->SetAttribute("value", StringConverter::toString(cv));
479                                                }
480                                                break;
481                                        case VES_TEXTURE_COORDINATES:
482                                                elem.baseVertexPointerToElement(pVert, &pFloat);
483                                                dataNode = 
484                                                        vertexNode->InsertEndChild(TiXmlElement("texcoord"))->ToElement();
485
486                                                switch(elem.getType())
487                        {
488                        case VET_FLOAT1:
489                                                dataNode->SetAttribute("u", StringConverter::toString(*pFloat++));
490                            break;
491                        case VET_FLOAT2:
492                                                dataNode->SetAttribute("u", StringConverter::toString(*pFloat++));
493                                                dataNode->SetAttribute("v", StringConverter::toString(*pFloat++));
494                            break;
495                        case VET_FLOAT3:
496                                                dataNode->SetAttribute("u", StringConverter::toString(*pFloat++));
497                                                dataNode->SetAttribute("v", StringConverter::toString(*pFloat++));
498                                                dataNode->SetAttribute("w", StringConverter::toString(*pFloat++));
499                            break;
500                        default:
501                            break;
502                        }
503                                                break;
504                    default:
505                        break;
506
507                                        }
508                                }
509                                pVert += vbuf->getVertexSize();
510                        }
511                        vbuf->unlock();
512                }
513
514    }
515    //---------------------------------------------------------------------
516    void XMLMeshSerializer::writeSkeletonLink(TiXmlElement* mMeshNode, const String& skelName)
517    {
518
519        TiXmlElement* skelNode = 
520            mMeshNode->InsertEndChild(TiXmlElement("skeletonlink"))->ToElement();
521        skelNode->SetAttribute("name", skelName);
522    }
523    //---------------------------------------------------------------------
524    void XMLMeshSerializer::writeBoneAssignment(TiXmlElement* mBoneAssignNode, const VertexBoneAssignment* assign)
525    {
526        TiXmlElement* assignNode = 
527            mBoneAssignNode->InsertEndChild(
528            TiXmlElement("vertexboneassignment"))->ToElement();
529
530        assignNode->SetAttribute("vertexindex", 
531            StringConverter::toString(assign->vertexIndex));
532        assignNode->SetAttribute("boneindex", 
533            StringConverter::toString(assign->boneIndex));
534        assignNode->SetAttribute("weight",
535            StringConverter::toString(assign->weight));
536
537
538    }
539    //---------------------------------------------------------------------
540    void XMLMeshSerializer::writeTextureAliases(TiXmlElement* mSubmeshesNode, const SubMesh* subMesh)
541    {
542        if (!subMesh->hasTextureAliases())
543            return; // do nothing
544
545        TiXmlElement* textureAliasesNode = 
546            mSubmeshesNode->InsertEndChild(TiXmlElement("textures"))->ToElement();
547
548        // use ogre map iterator
549        SubMesh::AliasTextureIterator aliasIterator = subMesh->getAliasTextureIterator();
550
551        while (aliasIterator.hasMoreElements())
552        {
553            TiXmlElement* aliasTextureNode = 
554                textureAliasesNode->InsertEndChild(TiXmlElement("texture"))->ToElement();
555            // iterator key is alias and value is texture name
556            aliasTextureNode->SetAttribute("alias", aliasIterator.peekNextKey());
557            aliasTextureNode->SetAttribute("name", aliasIterator.peekNextValue());
558            aliasIterator.moveNext();
559        }
560
561    }
562    //---------------------------------------------------------------------
563    void XMLMeshSerializer::readSubMeshes(TiXmlElement* mSubmeshesNode)
564    {
565        LogManager::getSingleton().logMessage("Reading submeshes...");
566
567        for (TiXmlElement* smElem = mSubmeshesNode->FirstChildElement();
568            smElem != 0; smElem = smElem->NextSiblingElement())
569        {
570            // All children should be submeshes
571            SubMesh* sm = mpMesh->createSubMesh();
572
573            const char* mat = smElem->Attribute("material");
574            if (mat)
575                sm->setMaterialName(mat);
576
577            // Read operation type
578            const char* optype = smElem->Attribute("operationtype");
579            if (optype)
580            {
581                if (!strcmp(optype, "triangle_list"))
582                {
583                    sm->operationType = RenderOperation::OT_TRIANGLE_LIST;
584                }
585                else if (!strcmp(optype, "triangle_fan"))
586                {
587                    sm->operationType = RenderOperation::OT_TRIANGLE_FAN;
588                }
589                else if (!strcmp(optype, "triangle_strip"))
590                {
591                    sm->operationType = RenderOperation::OT_TRIANGLE_STRIP;
592                }
593
594            }
595
596            const char* tmp = smElem->Attribute("usesharedvertices");
597            if (tmp)
598                sm->useSharedVertices = StringConverter::parseBool(tmp);
599            tmp = smElem->Attribute("use32bitindexes");
600            bool use32BitIndexes = false;
601            if (tmp)
602                use32BitIndexes = StringConverter::parseBool(tmp);
603           
604            // Faces
605            TiXmlElement* faces = smElem->FirstChildElement("faces");
606            size_t actualCount = 0;
607            for (TiXmlElement *faceElem = faces->FirstChildElement(); faceElem != 0; faceElem = faceElem->NextSiblingElement())
608            {
609                    actualCount++;
610            }
611            const char *claimedCount_ = faces->Attribute("count");
612            if (claimedCount_ && StringConverter::parseInt(claimedCount_)!=actualCount)
613            {
614                                StringUtil::StrStreamType str;
615                str << "WARNING: face count (" << actualCount << ") " <<
616                                        "is not as claimed (" << claimedCount_ << ")";
617                                LogManager::getSingleton().logMessage(str.str());
618            }
619
620
621            // Faces
622            if (sm->operationType == RenderOperation::OT_TRIANGLE_LIST)
623            {
624                    // tri list
625                    sm->indexData->indexCount = actualCount * 3;
626            } else {
627                    // tri strip or fan
628                    sm->indexData->indexCount = actualCount + 2;
629            }
630
631            // Allocate space
632            HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
633                createIndexBuffer(
634                    use32BitIndexes? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT, 
635                    sm->indexData->indexCount, 
636                    HardwareBuffer::HBU_DYNAMIC,
637                    false);
638            sm->indexData->indexBuffer = ibuf;
639            unsigned int *pInt;
640            unsigned short *pShort;
641            if (use32BitIndexes)
642            {
643                pInt = static_cast<unsigned int*>(
644                    ibuf->lock(HardwareBuffer::HBL_DISCARD));
645            }
646            else
647            {
648                pShort = static_cast<unsigned short*>(
649                    ibuf->lock(HardwareBuffer::HBL_DISCARD));
650            }
651            TiXmlElement* faceElem;
652            bool firstTri = true;
653            for (faceElem = faces->FirstChildElement();
654                faceElem != 0; faceElem = faceElem->NextSiblingElement())
655            {
656                if (use32BitIndexes)
657                {
658                    *pInt++ = StringConverter::parseInt(faceElem->Attribute("v1"));
659                    // only need all 3 vertices if it's a trilist or first tri
660                    if (sm->operationType == RenderOperation::OT_TRIANGLE_LIST || firstTri)
661                    {
662                        *pInt++ = StringConverter::parseInt(faceElem->Attribute("v2"));
663                        *pInt++ = StringConverter::parseInt(faceElem->Attribute("v3"));
664                    }
665                }
666                else
667                {
668                    *pShort++ = StringConverter::parseInt(faceElem->Attribute("v1"));
669                    // only need all 3 vertices if it's a trilist or first tri
670                    if (sm->operationType == RenderOperation::OT_TRIANGLE_LIST || firstTri)
671                    {
672                        *pShort++ = StringConverter::parseInt(faceElem->Attribute("v2"));
673                        *pShort++ = StringConverter::parseInt(faceElem->Attribute("v3"));
674                    }
675                }
676                firstTri = false;
677            }
678            ibuf->unlock();
679
680            // Geometry
681            if (!sm->useSharedVertices)
682            {
683                TiXmlElement* geomNode = smElem->FirstChildElement("geometry");
684                if (geomNode)
685                {
686                    sm->vertexData = new VertexData();
687                    readGeometry(geomNode, sm->vertexData);
688                }
689            }
690
691            // texture aliases
692            TiXmlElement* textureAliasesNode = smElem->FirstChildElement("textures");
693            if(textureAliasesNode)
694                readTextureAliases(textureAliasesNode, sm);
695
696            // Bone assignments
697            TiXmlElement* boneAssigns = smElem->FirstChildElement("boneassignments");
698            if(boneAssigns)
699                readBoneAssignments(boneAssigns, sm);
700
701        }
702        LogManager::getSingleton().logMessage("Submeshes done.");
703    }
704    //---------------------------------------------------------------------
705    void XMLMeshSerializer::readGeometry(TiXmlElement* mGeometryNode, VertexData* vertexData)
706    {
707        LogManager::getSingleton().logMessage("Reading geometry...");
708        unsigned char *pVert;
709        float *pFloat;
710        ARGB *pCol;
711
712        const char *claimedVertexCount_ = mGeometryNode->Attribute("vertexcount");
713        ptrdiff_t claimedVertexCount;
714        if (claimedVertexCount_)
715        {
716                claimedVertexCount =
717                        StringConverter::parseInt(claimedVertexCount_);
718        }
719        // Skip empty
720        if (claimedVertexCount_ && claimedVertexCount <= 0) return;
721       
722
723        VertexDeclaration* decl = vertexData->vertexDeclaration;
724        VertexBufferBinding* bind = vertexData->vertexBufferBinding;
725        unsigned short bufCount = 0;
726        unsigned short totalTexCoords = 0; // across all buffers
727
728        // Information for calculating bounds
729        Vector3 min, max, pos;
730        Real maxSquaredRadius = -1;
731        bool first = true;
732
733        // Iterate over all children (vertexbuffer entries)
734        for (TiXmlElement* vbElem = mGeometryNode->FirstChildElement();
735            vbElem != 0; vbElem = vbElem->NextSiblingElement())
736        {
737            size_t offset = 0;
738            // Skip non-vertexbuffer elems
739            if (stricmp(vbElem->Value(), "vertexbuffer")) continue;
740           
741            const char* attrib = vbElem->Attribute("positions");
742            if (attrib && StringConverter::parseBool(attrib))
743            {
744                // Add element
745                decl->addElement(bufCount, offset, VET_FLOAT3, VES_POSITION);
746                offset += VertexElement::getTypeSize(VET_FLOAT3);
747            }
748            attrib = vbElem->Attribute("normals");
749            if (attrib && StringConverter::parseBool(attrib))
750            {
751                // Add element
752                decl->addElement(bufCount, offset, VET_FLOAT3, VES_NORMAL);
753                offset += VertexElement::getTypeSize(VET_FLOAT3);
754            }
755                        attrib = vbElem->Attribute("tangents");
756                        if (attrib && StringConverter::parseBool(attrib))
757                        {
758                                // Add element
759                                decl->addElement(bufCount, offset, VET_FLOAT3, VES_TANGENT);
760                                offset += VertexElement::getTypeSize(VET_FLOAT3);
761                        }
762                        attrib = vbElem->Attribute("binormals");
763                        if (attrib && StringConverter::parseBool(attrib))
764                        {
765                                // Add element
766                                decl->addElement(bufCount, offset, VET_FLOAT3, VES_BINORMAL);
767                                offset += VertexElement::getTypeSize(VET_FLOAT3);
768                        }
769            attrib = vbElem->Attribute("colours_diffuse");
770            if (attrib && StringConverter::parseBool(attrib))
771            {
772                // Add element
773                decl->addElement(bufCount, offset, mColourElementType, VES_DIFFUSE);
774                offset += VertexElement::getTypeSize(mColourElementType);
775            }
776            attrib = vbElem->Attribute("colours_specular");
777            if (attrib && StringConverter::parseBool(attrib))
778            {
779                // Add element
780                decl->addElement(bufCount, offset, mColourElementType, VES_SPECULAR);
781                offset += VertexElement::getTypeSize(mColourElementType);
782            }
783            attrib = vbElem->Attribute("texture_coords");
784            if (attrib && StringConverter::parseInt(attrib))
785            {
786                unsigned short numTexCoords = StringConverter::parseInt(vbElem->Attribute("texture_coords"));
787                for (unsigned short tx = 0; tx < numTexCoords; ++tx)
788                {
789                    // NB set is local to this buffer, but will be translated into a
790                    // global set number across all vertex buffers
791                                        StringUtil::StrStreamType str;
792                                        str << "texture_coord_dimensions_" << tx;
793                    attrib = vbElem->Attribute(str.str().c_str());
794                    unsigned short dims;
795                    if (attrib)
796                    {
797                        dims = StringConverter::parseInt(attrib);
798                    }
799                    else
800                    {
801                        // Default
802                        dims = 2;
803                    }
804                    // Add element
805                    VertexElementType vtype = VertexElement::multiplyTypeCount(VET_FLOAT1, dims);
806                    decl->addElement(bufCount, offset, vtype, 
807                        VES_TEXTURE_COORDINATES, totalTexCoords++);
808                    offset += VertexElement::getTypeSize(vtype);
809                }
810            } 
811
812            // calculate how many vertexes there actually are
813            int actualVertexCount = 0;
814            for (TiXmlElement * vertexElem = vbElem->FirstChildElement(); vertexElem != 0; vertexElem = vertexElem->NextSiblingElement())
815            {
816                    actualVertexCount++;
817            }
818            if (claimedVertexCount_ && actualVertexCount!=claimedVertexCount)
819            {
820                                StringUtil::StrStreamType str;
821                                str << "WARNING: vertex count (" << actualVertexCount
822                                        << ") is not as claimed (" << claimedVertexCount_ << ")";
823                                LogManager::getSingleton().logMessage(str.str());
824            }
825
826            vertexData->vertexCount = actualVertexCount;
827            // Now create the vertex buffer
828            HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().
829                createVertexBuffer(offset, vertexData->vertexCount, 
830                    HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
831            // Bind it
832            bind->setBinding(bufCount, vbuf);
833            // Lock it
834            pVert = static_cast<unsigned char*>(
835                vbuf->lock(HardwareBuffer::HBL_DISCARD));
836
837            // Get the element list for this buffer alone
838            VertexDeclaration::VertexElementList elems = decl->findElementsBySource(bufCount);
839            // Now the buffer is set up, parse all the vertices
840            for (TiXmlElement* vertexElem = vbElem->FirstChildElement();
841            vertexElem != 0; vertexElem = vertexElem->NextSiblingElement())
842            {
843                // Now parse the elements, ensure they are all matched
844                VertexDeclaration::VertexElementList::const_iterator ielem, ielemend;
845                TiXmlElement* xmlElem;
846                TiXmlElement* texCoordElem = 0;
847                ielemend = elems.end();
848                for (ielem = elems.begin(); ielem != ielemend; ++ielem)
849                {
850                    const VertexElement& elem = *ielem;
851                    // Find child for this element
852                    switch(elem.getSemantic())
853                    {
854                    case VES_POSITION:
855                        xmlElem = vertexElem->FirstChildElement("position");
856                        if (!xmlElem)
857                        {
858                            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <position> element.",
859                                "XMLSerializer::readGeometry");
860                        }
861                        elem.baseVertexPointerToElement(pVert, &pFloat);
862
863                        *pFloat++ = StringConverter::parseReal(
864                            xmlElem->Attribute("x"));
865                        *pFloat++ = StringConverter::parseReal(
866                            xmlElem->Attribute("y"));
867                        *pFloat++ = StringConverter::parseReal(
868                            xmlElem->Attribute("z"));
869
870                        pos.x = StringConverter::parseReal(
871                            xmlElem->Attribute("x"));
872                        pos.y = StringConverter::parseReal(
873                            xmlElem->Attribute("y"));
874                        pos.z = StringConverter::parseReal(
875                            xmlElem->Attribute("z"));
876                       
877                        if (first)
878                        {
879                            min = max = pos;
880                            maxSquaredRadius = pos.squaredLength();
881                            first = false;
882                        }
883                        else
884                        {
885                            min.makeFloor(pos);
886                            max.makeCeil(pos);
887                            maxSquaredRadius = std::max(pos.squaredLength(), maxSquaredRadius);
888                        }
889                        break;
890                    case VES_NORMAL:
891                        xmlElem = vertexElem->FirstChildElement("normal");
892                        if (!xmlElem)
893                        {
894                            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <normal> element.",
895                                "XMLSerializer::readGeometry");
896                        }
897                        elem.baseVertexPointerToElement(pVert, &pFloat);
898
899                        *pFloat++ = StringConverter::parseReal(
900                            xmlElem->Attribute("x"));
901                        *pFloat++ = StringConverter::parseReal(
902                            xmlElem->Attribute("y"));
903                        *pFloat++ = StringConverter::parseReal(
904                            xmlElem->Attribute("z"));
905                        break;
906                                        case VES_TANGENT:
907                                                xmlElem = vertexElem->FirstChildElement("tangent");
908                                                if (!xmlElem)
909                                                {
910                                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <tangent> element.",
911                                                                "XMLSerializer::readGeometry");
912                                                }
913                                                elem.baseVertexPointerToElement(pVert, &pFloat);
914
915                                                *pFloat++ = StringConverter::parseReal(
916                                                        xmlElem->Attribute("x"));
917                                                *pFloat++ = StringConverter::parseReal(
918                                                        xmlElem->Attribute("y"));
919                                                *pFloat++ = StringConverter::parseReal(
920                                                        xmlElem->Attribute("z"));
921                                                break;
922                                        case VES_BINORMAL:
923                                                xmlElem = vertexElem->FirstChildElement("binormal");
924                                                if (!xmlElem)
925                                                {
926                                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <binormal> element.",
927                                                                "XMLSerializer::readGeometry");
928                                                }
929                                                elem.baseVertexPointerToElement(pVert, &pFloat);
930
931                                                *pFloat++ = StringConverter::parseReal(
932                                                        xmlElem->Attribute("x"));
933                                                *pFloat++ = StringConverter::parseReal(
934                                                        xmlElem->Attribute("y"));
935                                                *pFloat++ = StringConverter::parseReal(
936                                                        xmlElem->Attribute("z"));
937                                                break;
938                    case VES_DIFFUSE:
939                        xmlElem = vertexElem->FirstChildElement("colour_diffuse");
940                        if (!xmlElem)
941                        {
942                            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <colour_diffuse> element.",
943                                "XMLSerializer::readGeometry");
944                        }
945                        elem.baseVertexPointerToElement(pVert, &pCol);
946                                                {
947                                                        ColourValue cv;
948                                                        cv = StringConverter::parseColourValue(
949                                                                xmlElem->Attribute("value"));
950                                                        *pCol++ = VertexElement::convertColourValue(cv, mColourElementType);
951                                                }
952                        break;
953                    case VES_SPECULAR:
954                        xmlElem = vertexElem->FirstChildElement("colour_specular");
955                        if (!xmlElem)
956                        {
957                            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <colour_specular> element.",
958                                "XMLSerializer::readGeometry");
959                        }
960                        elem.baseVertexPointerToElement(pVert, &pCol);
961                                                {
962                                                        ColourValue cv;
963                                                        cv = StringConverter::parseColourValue(
964                                                                xmlElem->Attribute("value"));
965                                                        *pCol++ = VertexElement::convertColourValue(cv, mColourElementType);
966                                                }
967                        break;
968                    case VES_TEXTURE_COORDINATES:
969                        if (!texCoordElem)
970                        {
971                            // Get first texcoord
972                            xmlElem = vertexElem->FirstChildElement("texcoord");
973                        }
974                        else
975                        {
976                            // Get next texcoord
977                            xmlElem = texCoordElem->NextSiblingElement("texcoord");
978                        }
979                        if (!xmlElem)
980                        {
981                            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Missing <texcoord> element.",
982                                "XMLSerializer::readGeometry");
983                        }
984                                                // Record the latest texture coord entry
985                                                texCoordElem = xmlElem;
986                        elem.baseVertexPointerToElement(pVert, &pFloat);
987
988                        *pFloat++ = StringConverter::parseReal(
989                            xmlElem->Attribute("u"));
990                        if (VertexElement::getTypeCount(elem.getType()) > 1)
991                        {
992                            *pFloat++ = StringConverter::parseReal(
993                                xmlElem->Attribute("v"));
994                        }
995                        if (VertexElement::getTypeCount(elem.getType()) > 2)
996                        {
997                            *pFloat++ = StringConverter::parseReal(
998                                xmlElem->Attribute("w"));
999                        }
1000
1001                        break;
1002                    default:
1003                        break;
1004                    }
1005                } // semantic
1006                pVert += vbuf->getVertexSize();
1007            } // vertex
1008            bufCount++;
1009            vbuf->unlock();
1010        } // vertexbuffer
1011
1012        // Set bounds
1013        const AxisAlignedBox& currBox = mpMesh->getBounds();
1014        Real currRadius = mpMesh->getBoundingSphereRadius();
1015        if (currBox.isNull())
1016        {
1017            //do not pad the bounding box
1018            mpMesh->_setBounds(AxisAlignedBox(min, max), false);
1019            mpMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
1020        }
1021        else
1022        {
1023            AxisAlignedBox newBox(min, max);
1024            newBox.merge(currBox);
1025            //do not pad the bounding box
1026            mpMesh->_setBounds(newBox, false);
1027            mpMesh->_setBoundingSphereRadius(std::max(Math::Sqrt(maxSquaredRadius), currRadius));
1028        }
1029       
1030
1031        LogManager::getSingleton().logMessage("Geometry done...");
1032    }
1033    //---------------------------------------------------------------------
1034    void XMLMeshSerializer::readSkeletonLink(TiXmlElement* mSkelNode)
1035    {
1036        mpMesh->setSkeletonName(mSkelNode->Attribute("name"));
1037    }
1038    //---------------------------------------------------------------------
1039    void XMLMeshSerializer::readBoneAssignments(TiXmlElement* mBoneAssignmentsNode)
1040    {
1041        LogManager::getSingleton().logMessage("Reading bone assignments...");
1042
1043        // Iterate over all children (vertexboneassignment entries)
1044        for (TiXmlElement* elem = mBoneAssignmentsNode->FirstChildElement();
1045        elem != 0; elem = elem->NextSiblingElement())
1046        {
1047            VertexBoneAssignment vba;
1048            vba.vertexIndex = StringConverter::parseInt(
1049                elem->Attribute("vertexindex"));
1050            vba.boneIndex = StringConverter::parseInt(
1051                elem->Attribute("boneindex"));
1052            vba.weight= StringConverter::parseReal(
1053                elem->Attribute("weight"));
1054
1055            mpMesh->addBoneAssignment(vba);
1056        }
1057
1058        LogManager::getSingleton().logMessage("Bone assignments done.");
1059    }
1060    //---------------------------------------------------------------------
1061    void XMLMeshSerializer::readTextureAliases(TiXmlElement* mTextureAliasesNode, SubMesh* subMesh)
1062    {
1063        LogManager::getSingleton().logMessage("Reading sub mesh texture aliases...");
1064
1065        // Iterate over all children (texture entries)
1066        for (TiXmlElement* elem = mTextureAliasesNode->FirstChildElement();
1067             elem != 0; elem = elem->NextSiblingElement())
1068        {
1069            // pass alias and texture name to submesh
1070            // read attribute "alias"
1071            String alias = elem->Attribute("alias");
1072            // read attribute "name"
1073            String name = elem->Attribute("name");
1074
1075            subMesh->addTextureAlias(alias, name);
1076        }
1077
1078        LogManager::getSingleton().logMessage("Texture aliases done.");
1079    }
1080    //---------------------------------------------------------------------
1081        void XMLMeshSerializer::readSubMeshNames(TiXmlElement* mMeshNamesNode, Mesh *sm)
1082        {
1083                LogManager::getSingleton().logMessage("Reading mesh names...");
1084
1085                // Iterate over all children (vertexboneassignment entries)
1086                for (TiXmlElement* elem = mMeshNamesNode->FirstChildElement();
1087                        elem != 0; elem = elem->NextSiblingElement())
1088                {
1089                        String meshName = elem->Attribute("name");
1090                        int index = StringConverter::parseInt(elem->Attribute("index"));
1091
1092                        sm->nameSubMesh(meshName, index);
1093                }
1094
1095                LogManager::getSingleton().logMessage("Mesh names done.");
1096        }
1097    //---------------------------------------------------------------------
1098    void XMLMeshSerializer::readBoneAssignments(TiXmlElement* mBoneAssignmentsNode, SubMesh* sm)
1099    {
1100        LogManager::getSingleton().logMessage("Reading bone assignments...");
1101        // Iterate over all children (vertexboneassignment entries)
1102        for (TiXmlElement* elem = mBoneAssignmentsNode->FirstChildElement();
1103        elem != 0; elem = elem->NextSiblingElement())
1104        {
1105            VertexBoneAssignment vba;
1106            vba.vertexIndex = StringConverter::parseInt(
1107                elem->Attribute("vertexindex"));
1108            vba.boneIndex = StringConverter::parseInt(
1109                elem->Attribute("boneindex"));
1110            vba.weight= StringConverter::parseReal(
1111                elem->Attribute("weight"));
1112
1113            sm->addBoneAssignment(vba);
1114        }
1115        LogManager::getSingleton().logMessage("Bone assignments done.");
1116    }
1117    //---------------------------------------------------------------------
1118        void XMLMeshSerializer::writeLodInfo(TiXmlElement* mMeshNode, const Mesh* pMesh)
1119        {
1120        TiXmlElement* lodNode = 
1121            mMeshNode->InsertEndChild(TiXmlElement("levelofdetail"))->ToElement();
1122
1123                unsigned short numLvls = pMesh->getNumLodLevels();
1124                bool manual = pMesh->isLodManual();
1125                lodNode->SetAttribute("numlevels", StringConverter::toString(numLvls));
1126                lodNode->SetAttribute("manual", StringConverter::toString(manual));
1127
1128                // Iterate from level 1, not 0 (full detail)
1129                for (unsigned short i = 1; i < numLvls; ++i)
1130                {
1131                        const MeshLodUsage& usage = pMesh->getLodLevel(i);
1132                        if (manual)
1133                        {
1134                                writeLodUsageManual(lodNode, i, usage);
1135                        }
1136                        else
1137                        {
1138                                writeLodUsageGenerated(lodNode, i, usage, pMesh);
1139                        }
1140                }
1141
1142        }
1143    //---------------------------------------------------------------------
1144    void XMLMeshSerializer::writeSubMeshNames(TiXmlElement* mMeshNode, const Mesh* m)
1145    {
1146        const Mesh::SubMeshNameMap& nameMap = m->getSubMeshNameMap();
1147        if (nameMap.empty())
1148            return; // do nothing
1149
1150        TiXmlElement* namesNode = 
1151            mMeshNode->InsertEndChild(TiXmlElement("submeshnames"))->ToElement();
1152        Mesh::SubMeshNameMap::const_iterator i, iend;
1153        iend = nameMap.end();
1154        for (i = nameMap.begin(); i != iend; ++i)
1155        {
1156            TiXmlElement* subNameNode = 
1157                namesNode->InsertEndChild(TiXmlElement("submeshname"))->ToElement();
1158
1159            subNameNode->SetAttribute("name", i->first);
1160            subNameNode->SetAttribute("index", 
1161                StringConverter::toString(i->second));
1162        }
1163
1164    }
1165    //---------------------------------------------------------------------
1166        void XMLMeshSerializer::writeLodUsageManual(TiXmlElement* usageNode, 
1167                unsigned short levelNum, const MeshLodUsage& usage)
1168        {
1169                TiXmlElement* manualNode = 
1170                        usageNode->InsertEndChild(TiXmlElement("lodmanual"))->ToElement();
1171
1172                manualNode->SetAttribute("fromdepthsquared", 
1173                        StringConverter::toString(usage.fromDepthSquared));
1174                manualNode->SetAttribute("meshname", usage.manualName);
1175
1176        }
1177    //---------------------------------------------------------------------
1178        void XMLMeshSerializer::writeLodUsageGenerated(TiXmlElement* usageNode, 
1179                unsigned short levelNum,  const MeshLodUsage& usage, 
1180                const Mesh* pMesh)
1181        {
1182                TiXmlElement* generatedNode = 
1183                        usageNode->InsertEndChild(TiXmlElement("lodgenerated"))->ToElement();
1184                generatedNode->SetAttribute("fromdepthsquared", 
1185                        StringConverter::toString(usage.fromDepthSquared));
1186
1187                // Iterate over submeshes at this level
1188                unsigned short numsubs = pMesh->getNumSubMeshes();
1189
1190                for (unsigned short subi = 0; subi < numsubs; ++subi)
1191                {
1192                        TiXmlElement* subNode = 
1193                                generatedNode->InsertEndChild(TiXmlElement("lodfacelist"))->ToElement();
1194                        SubMesh* sub = pMesh->getSubMesh(subi);
1195                        subNode->SetAttribute("submeshindex", StringConverter::toString(subi));
1196                        // NB level - 1 because SubMeshes don't store the first index in geometry
1197                    IndexData* facedata = sub->mLodFaceList[levelNum - 1];
1198                        subNode->SetAttribute("numfaces", StringConverter::toString(facedata->indexCount / 3));
1199
1200                        // Write each face in turn
1201                    bool use32BitIndexes = (facedata->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
1202
1203            // Write each face in turn
1204                    unsigned int* pInt;
1205                    unsigned short* pShort;
1206                    HardwareIndexBufferSharedPtr ibuf = facedata->indexBuffer;
1207                    if (use32BitIndexes)
1208                    {
1209                            pInt = static_cast<unsigned int*>(
1210                                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); 
1211                    }
1212                    else
1213                    {
1214                            pShort = static_cast<unsigned short*>(
1215                                    ibuf->lock(HardwareBuffer::HBL_READ_ONLY)); 
1216                    }
1217                       
1218                        for (size_t f = 0; f < facedata->indexCount; f += 3)
1219                        {
1220                                TiXmlElement* faceNode = 
1221                                        subNode->InsertEndChild(TiXmlElement("face"))->ToElement();
1222                if (use32BitIndexes)
1223                {
1224                                    faceNode->SetAttribute("v1", StringConverter::toString(*pInt++));
1225                                    faceNode->SetAttribute("v2", StringConverter::toString(*pInt++));
1226                                    faceNode->SetAttribute("v3", StringConverter::toString(*pInt++));
1227                }
1228                else
1229                {
1230                                    faceNode->SetAttribute("v1", StringConverter::toString(*pShort++));
1231                                    faceNode->SetAttribute("v2", StringConverter::toString(*pShort++));
1232                                    faceNode->SetAttribute("v3", StringConverter::toString(*pShort++));
1233                }
1234
1235                        }
1236
1237
1238
1239                }
1240
1241        }
1242    //---------------------------------------------------------------------
1243        void XMLMeshSerializer::writeExtremes(TiXmlElement* mMeshNode, const Mesh* m)
1244        {
1245                TiXmlElement* extremesNode = NULL;
1246                int idx = 0;
1247                for (Mesh::SubMeshIterator i = ((Mesh &)*m).getSubMeshIterator ();
1248                         i.hasMoreElements (); i.moveNext (), ++idx)
1249                {
1250                        SubMesh *sm = i.peekNext ();
1251                        if (sm->extremityPoints.empty())
1252                                continue; // do nothing
1253
1254                        if (!extremesNode)
1255                                extremesNode = mMeshNode->InsertEndChild(TiXmlElement("extremes"))->ToElement();
1256
1257                        TiXmlElement* submeshNode =
1258                                extremesNode->InsertEndChild(TiXmlElement("submesh_extremes"))->ToElement();
1259
1260                        submeshNode->SetAttribute("index",  StringConverter::toString(idx));
1261
1262                        for (std::vector<Vector3>::const_iterator v = sm->extremityPoints.begin ();
1263                                 v != sm->extremityPoints.end (); ++v)
1264                        {
1265                                TiXmlElement* vert = submeshNode->InsertEndChild(
1266                                        TiXmlElement("position"))->ToElement();
1267                                vert->SetAttribute("x", StringConverter::toString(v->x));
1268                                vert->SetAttribute("y", StringConverter::toString(v->y));
1269                                vert->SetAttribute("z", StringConverter::toString(v->z));
1270                        }
1271                }
1272        }
1273        //---------------------------------------------------------------------
1274        void XMLMeshSerializer::readLodInfo(TiXmlElement*  lodNode)
1275        {
1276               
1277        LogManager::getSingleton().logMessage("Parsing LOD information...");
1278
1279                const char* val = lodNode->Attribute("numlevels");
1280                unsigned short numLevels = static_cast<unsigned short>(
1281                        StringConverter::parseUnsignedInt(val));
1282
1283                val = lodNode->Attribute("manual");
1284                bool manual = StringConverter::parseBool(val);
1285
1286                // Set up the basic structures
1287                mpMesh->_setLodInfo(numLevels, manual);
1288
1289                // Parse the detail, start from 1 (the first sub-level of detail)
1290                unsigned short i = 1;
1291                TiXmlElement* usageElem;
1292                if (manual)
1293                {
1294                        usageElem = lodNode->FirstChildElement("lodmanual");
1295                }
1296                else
1297                {
1298                        usageElem = lodNode->FirstChildElement("lodgenerated");
1299                }
1300                while (usageElem)
1301                {
1302                        if (manual)
1303                        {
1304                                readLodUsageManual(usageElem, i);
1305                                usageElem = usageElem->NextSiblingElement();
1306                        }
1307                        else
1308                        {
1309                                readLodUsageGenerated(usageElem, i);
1310                                usageElem = usageElem->NextSiblingElement();
1311                        }
1312                        ++i;
1313                }
1314               
1315        LogManager::getSingleton().logMessage("LOD information done.");
1316               
1317        }
1318    //---------------------------------------------------------------------
1319        void XMLMeshSerializer::readLodUsageManual(TiXmlElement* manualNode, unsigned short index)
1320        {
1321                MeshLodUsage usage;
1322                const char* val = manualNode->Attribute("fromdepthsquared");
1323                usage.fromDepthSquared = StringConverter::parseReal(val);
1324                usage.manualName = manualNode->Attribute("meshname");
1325        usage.edgeData = NULL;
1326
1327                mpMesh->_setLodUsage(index, usage);
1328        }
1329    //---------------------------------------------------------------------
1330        void XMLMeshSerializer::readLodUsageGenerated(TiXmlElement* genNode, unsigned short index)
1331        {
1332                MeshLodUsage usage;
1333                const char* val = genNode->Attribute("fromdepthsquared");
1334                usage.fromDepthSquared = StringConverter::parseReal(val);
1335                usage.manualMesh.setNull();
1336                usage.manualName = "";
1337        usage.edgeData = NULL;
1338
1339                mpMesh->_setLodUsage(index, usage);
1340
1341                // Read submesh face lists
1342                TiXmlElement* faceListElem = genNode->FirstChildElement("lodfacelist");
1343                while (faceListElem)
1344                {
1345                        val = faceListElem->Attribute("submeshindex");
1346                        unsigned short subidx = StringConverter::parseUnsignedInt(val);
1347                        val = faceListElem->Attribute("numfaces");
1348                        unsigned short numFaces = StringConverter::parseUnsignedInt(val);
1349            // use of 32bit indexes depends on submesh
1350            HardwareIndexBuffer::IndexType itype = 
1351                mpMesh->getSubMesh(subidx)->indexData->indexBuffer->getType();
1352            bool use32bitindexes = (itype == HardwareIndexBuffer::IT_32BIT);
1353
1354            // Assign memory: this will be deleted by the submesh
1355            HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
1356                createIndexBuffer(
1357                    itype, numFaces * 3, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1358
1359            unsigned short *pShort;
1360            unsigned int *pInt;
1361            if (use32bitindexes)
1362            {
1363                pInt = static_cast<unsigned int*>(
1364                    ibuf->lock(HardwareBuffer::HBL_DISCARD));
1365            }
1366            else
1367            {
1368                pShort = static_cast<unsigned short*>(
1369                    ibuf->lock(HardwareBuffer::HBL_DISCARD));
1370            }
1371            TiXmlElement* faceElem = faceListElem->FirstChildElement("face");
1372                        for (unsigned int face = 0; face < numFaces; ++face, faceElem = faceElem->NextSiblingElement())
1373                        {
1374                if (use32bitindexes)
1375                {
1376                    val = faceElem->Attribute("v1");
1377                                    *pInt++ = StringConverter::parseUnsignedInt(val);
1378                                    val = faceElem->Attribute("v2");
1379                                    *pInt++ = StringConverter::parseUnsignedInt(val);
1380                                    val = faceElem->Attribute("v3");
1381                                    *pInt++ = StringConverter::parseUnsignedInt(val);
1382                }
1383                else
1384                {
1385                    val = faceElem->Attribute("v1");
1386                                    *pShort++ = StringConverter::parseUnsignedInt(val);
1387                                    val = faceElem->Attribute("v2");
1388                                    *pShort++ = StringConverter::parseUnsignedInt(val);
1389                                    val = faceElem->Attribute("v3");
1390                                    *pShort++ = StringConverter::parseUnsignedInt(val);
1391                }
1392
1393                        }
1394
1395            ibuf->unlock();
1396                        IndexData* facedata = new IndexData(); // will be deleted by SubMesh
1397                        facedata->indexCount = numFaces * 3;
1398            facedata->indexStart = 0;
1399            facedata->indexBuffer = ibuf;
1400                        mpMesh->_setSubMeshLodFaceList(subidx, index, facedata);
1401
1402                        faceListElem = faceListElem->NextSiblingElement();
1403                }
1404       
1405        }
1406        //-----------------------------------------------------------------------------
1407        void XMLMeshSerializer::readExtremes(TiXmlElement* extremesNode, Mesh *m)
1408        {
1409                LogManager::getSingleton().logMessage("Reading extremes...");
1410
1411                // Iterate over all children (submesh_extreme list)
1412                for (TiXmlElement* elem = extremesNode->FirstChildElement();
1413                         elem != 0; elem = elem->NextSiblingElement())
1414                {
1415                        int index = StringConverter::parseInt(elem->Attribute("index"));
1416
1417                        SubMesh *sm = m->getSubMesh(index);
1418                        sm->extremityPoints.clear ();
1419                        for (TiXmlElement* vert = elem->FirstChildElement();
1420                                 vert != 0; vert = vert->NextSiblingElement())
1421                        {
1422                                Vector3 v;
1423                                v.x = StringConverter::parseReal(vert->Attribute("x"));
1424                                v.y = StringConverter::parseReal(vert->Attribute("y"));
1425                                v.z = StringConverter::parseReal(vert->Attribute("z"));
1426                                sm->extremityPoints.push_back (v);
1427                        }
1428                }
1429
1430                LogManager::getSingleton().logMessage("Extremes done.");
1431        }
1432        //-----------------------------------------------------------------------------
1433        void XMLMeshSerializer::readPoses(TiXmlElement* posesNode, Mesh *m)
1434        {
1435                TiXmlElement* poseNode = posesNode->FirstChildElement("pose");
1436
1437                while (poseNode)
1438                {
1439                        const char* target = poseNode->Attribute("target");
1440                        if (!target)
1441                        {
1442                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1443                                        "Required attribute 'target' missing on pose", 
1444                                        "XMLMeshSerializer::readPoses");
1445                        }
1446                        unsigned short targetID;
1447                        if(String(target) == "mesh")
1448                        {
1449                                targetID = 0;
1450                        }
1451                        else
1452                        {
1453                                // submesh, get index
1454                                const char* val = poseNode->Attribute("index");
1455                                if (!val)
1456                                {
1457                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1458                                                "Required attribute 'index' missing on pose", 
1459                                                "XMLMeshSerializer::readPoses");
1460                                }
1461                                unsigned short submeshIndex = static_cast<unsigned short>(
1462                                        StringConverter::parseUnsignedInt(val));
1463
1464                                targetID = submeshIndex + 1;
1465                        }
1466
1467                        String name;
1468                        const char* val = poseNode->Attribute("name");
1469                        if (val)
1470                                name = val;
1471                        Pose* pose = m->createPose(targetID, name);
1472
1473                        TiXmlElement* poseOffsetNode = poseNode->FirstChildElement("poseoffset");
1474                        while (poseOffsetNode)
1475                        {
1476                                uint index = StringConverter::parseUnsignedInt(
1477                                        poseOffsetNode->Attribute("index"));
1478                                Vector3 offset;
1479                                offset.x = StringConverter::parseReal(poseOffsetNode->Attribute("x"));
1480                                offset.y = StringConverter::parseReal(poseOffsetNode->Attribute("y"));
1481                                offset.z = StringConverter::parseReal(poseOffsetNode->Attribute("z"));
1482
1483                                pose->addVertex(index, offset);
1484
1485                                poseOffsetNode = poseOffsetNode->NextSiblingElement();
1486                        }
1487
1488                        poseNode = poseNode->NextSiblingElement();
1489
1490                }
1491
1492
1493        }
1494        //-----------------------------------------------------------------------------
1495        void XMLMeshSerializer::readAnimations(TiXmlElement* mAnimationsNode, Mesh *pMesh)
1496        {
1497                TiXmlElement* animElem = mAnimationsNode->FirstChildElement("animation");
1498                while (animElem)
1499                {
1500                        String name = animElem->Attribute("name");
1501                        const char* charLen = animElem->Attribute("length");
1502                        Real len = StringConverter::parseReal(charLen);
1503
1504                        Animation* anim = pMesh->createAnimation(name, len);
1505
1506                        TiXmlElement* tracksNode = animElem->FirstChildElement("tracks");
1507                        if (tracksNode)
1508                        {
1509                                readTracks(tracksNode, pMesh, anim);
1510                        }
1511
1512                        animElem = animElem->NextSiblingElement();
1513
1514                }
1515
1516
1517        }
1518        //-----------------------------------------------------------------------------
1519        void XMLMeshSerializer::readTracks(TiXmlElement* tracksNode, Mesh *m, Animation* anim)
1520        {
1521                TiXmlElement* trackNode = tracksNode->FirstChildElement("track");
1522                while (trackNode)
1523                {
1524                        String target = trackNode->Attribute("target");
1525                        unsigned short targetID;
1526                        VertexData* vertexData = 0;
1527                        if(target == "mesh")
1528                        {
1529                                targetID = 0;
1530                                vertexData = m->sharedVertexData;
1531                        }
1532                        else
1533                        {
1534                                // submesh, get index
1535                                const char* val = trackNode->Attribute("index");
1536                                if (!val)
1537                                {
1538                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1539                                                "Required attribute 'index' missing on submesh track", 
1540                                                "XMLMeshSerializer::readTracks");
1541                                }
1542                                unsigned short submeshIndex = static_cast<unsigned short>(
1543                                        StringConverter::parseUnsignedInt(val));
1544
1545                                targetID = submeshIndex + 1;
1546                                vertexData = m->getSubMesh(submeshIndex)->vertexData;
1547
1548                        }
1549
1550                        if (!vertexData)
1551                        {
1552                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1553                                        "Track cannot be created for " + target + " since VertexData "
1554                                        "does not exist at the specified index", 
1555                                        "XMLMeshSerializer::readTracks");
1556                        }
1557
1558                        // Get type
1559                        VertexAnimationType animType = VAT_NONE;
1560                        String strAnimType = trackNode->Attribute("type");
1561                        if (strAnimType == "morph")
1562                        {
1563                                animType = VAT_MORPH;
1564                        }
1565                        else if (strAnimType == "pose")
1566                        {
1567                                animType = VAT_POSE;
1568                        }
1569                        else
1570                        {
1571                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1572                                        "Unrecognised animation track type '" + strAnimType + "'",
1573                                        "XMLMeshSerializer::readTracks");
1574                        }
1575
1576                        // Create track
1577                        VertexAnimationTrack* track = 
1578                                anim->createVertexTrack(targetID, vertexData, animType);
1579
1580                        TiXmlElement* keyframesNode = trackNode->FirstChildElement("keyframes");
1581                        if (keyframesNode)
1582                        {
1583                                if (track->getAnimationType() == VAT_MORPH)
1584                                {
1585                                        readMorphKeyFrames(keyframesNode, track, vertexData->vertexCount);
1586                                }
1587                                else // VAT_POSE
1588                                {
1589                                        readPoseKeyFrames(keyframesNode, track);
1590                                }
1591                        }
1592
1593                        trackNode = trackNode->NextSiblingElement();
1594                }
1595        }
1596        //-----------------------------------------------------------------------------
1597        void XMLMeshSerializer::readMorphKeyFrames(TiXmlElement* keyframesNode, 
1598                VertexAnimationTrack* track, size_t vertexCount)
1599        {
1600                TiXmlElement* keyNode = keyframesNode->FirstChildElement("keyframe");
1601                while (keyNode)
1602                {
1603                        const char* val = keyNode->Attribute("time");
1604                        if (!val)
1605                        {
1606                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1607                                        "Required attribute 'time' missing on keyframe", 
1608                                        "XMLMeshSerializer::readKeyFrames");
1609                        }
1610                        Real time = StringConverter::parseReal(val);
1611
1612                        VertexMorphKeyFrame* kf = track->createVertexMorphKeyFrame(time);
1613
1614                        // create a vertex buffer
1615                        HardwareVertexBufferSharedPtr vbuf = 
1616                                HardwareBufferManager::getSingleton().createVertexBuffer(
1617                                VertexElement::getTypeSize(VET_FLOAT3), vertexCount, 
1618                                HardwareBuffer::HBU_STATIC, true);
1619
1620                        float* pFloat = static_cast<float*>(
1621                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
1622
1623
1624                        TiXmlElement* posNode = keyNode->FirstChildElement("position");
1625                        for (size_t v = 0; v < vertexCount; ++v)
1626                        {
1627                                if (!posNode)
1628                                {
1629                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1630                                                "Not enough 'position' elements under keyframe", 
1631                                                "XMLMeshSerializer::readKeyFrames");
1632
1633                                }
1634
1635                                *pFloat++ = StringConverter::parseReal(
1636                                        posNode->Attribute("x"));
1637                                *pFloat++ = StringConverter::parseReal(
1638                                        posNode->Attribute("y"));
1639                                *pFloat++ = StringConverter::parseReal(
1640                                        posNode->Attribute("z"));
1641
1642
1643                                posNode = posNode->NextSiblingElement("position");
1644                        }
1645
1646                        vbuf->unlock();
1647
1648                        kf->setVertexBuffer(vbuf);
1649                               
1650
1651                        keyNode = keyNode->NextSiblingElement();
1652                }
1653
1654
1655        }
1656        //-----------------------------------------------------------------------------
1657        void XMLMeshSerializer::readPoseKeyFrames(TiXmlElement* keyframesNode, VertexAnimationTrack* track)
1658        {
1659                TiXmlElement* keyNode = keyframesNode->FirstChildElement("keyframe");
1660                while (keyNode)
1661                {
1662                        const char* val = keyNode->Attribute("time");
1663                        if (!val)
1664                        {
1665                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1666                                        "Required attribute 'time' missing on keyframe", 
1667                                        "XMLMeshSerializer::readKeyFrames");
1668                        }
1669                        Real time = StringConverter::parseReal(val);
1670
1671                        VertexPoseKeyFrame* kf = track->createVertexPoseKeyFrame(time);
1672
1673                        // Read all pose references
1674                        TiXmlElement* poseRefNode = keyNode->FirstChildElement("poseref");
1675                        while (poseRefNode)
1676                        {
1677                                const char* val = poseRefNode->Attribute("poseindex");
1678                                if (!val)
1679                                {
1680                                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
1681                                                "Required attribute 'poseindex' missing on poseref", 
1682                                                "XMLMeshSerializer::readPoseKeyFrames");
1683                                }
1684                                unsigned short poseIndex = StringConverter::parseUnsignedInt(val);
1685                                Real influence = 1.0f;
1686                                val = poseRefNode->Attribute("influence");
1687                                if (val)
1688                                {
1689                                        influence = StringConverter::parseReal(val);
1690                                }
1691
1692                                kf->addPoseReference(poseIndex, influence);
1693
1694                                poseRefNode = poseRefNode->NextSiblingElement();
1695                        }
1696
1697                        keyNode = keyNode->NextSiblingElement();
1698                }
1699
1700        }
1701        //-----------------------------------------------------------------------------
1702        void XMLMeshSerializer::writePoses(TiXmlElement* meshNode, const Mesh* m)
1703        {
1704                if (m->getPoseCount() == 0)
1705                        return;
1706
1707                TiXmlElement* posesNode = 
1708                        meshNode->InsertEndChild(TiXmlElement("poses"))->ToElement();
1709
1710                Mesh::ConstPoseIterator poseIt = m->getPoseIterator();
1711                while (poseIt.hasMoreElements())
1712                {
1713                        const Pose* pose = poseIt.getNext();
1714                        TiXmlElement* poseNode = 
1715                                posesNode->InsertEndChild(TiXmlElement("pose"))->ToElement();
1716                        unsigned short target = pose->getTarget();
1717                        if (target == 0)
1718                        {
1719                                // Main mesh
1720                                poseNode->SetAttribute("target", "mesh");
1721                        }
1722                        else
1723                        {
1724                                // Submesh - rebase index
1725                                poseNode->SetAttribute("target", "submesh");
1726                                poseNode->SetAttribute("index", 
1727                                        StringConverter::toString(target - 1));
1728                        }
1729                        poseNode->SetAttribute("name", pose->getName());
1730
1731                        Pose::ConstVertexOffsetIterator vit = pose->getVertexOffsetIterator();
1732                        while (vit.hasMoreElements())
1733                        {
1734                                TiXmlElement* poseOffsetElement = poseNode->InsertEndChild(
1735                                        TiXmlElement("poseoffset"))->ToElement();
1736
1737                                poseOffsetElement->SetAttribute("index", 
1738                                        StringConverter::toString(vit.peekNextKey()));
1739
1740                                Vector3 offset = vit.getNext();
1741                                poseOffsetElement->SetAttribute("x", StringConverter::toString(offset.x));
1742                                poseOffsetElement->SetAttribute("y", StringConverter::toString(offset.y));
1743                                poseOffsetElement->SetAttribute("z", StringConverter::toString(offset.z));
1744
1745
1746                        }
1747
1748                }
1749
1750        }
1751        //-----------------------------------------------------------------------------
1752        void XMLMeshSerializer::writeAnimations(TiXmlElement* meshNode, const Mesh* m)
1753        {
1754                // Skip if no animation
1755                if (!m->hasVertexAnimation())
1756                        return;
1757
1758                TiXmlElement* animationsNode = 
1759                        meshNode->InsertEndChild(TiXmlElement("animations"))->ToElement();
1760
1761                for (unsigned short a = 0; a < m->getNumAnimations(); ++a)
1762                {
1763                        Animation* anim = m->getAnimation(a);
1764
1765                        TiXmlElement* animNode = 
1766                                animationsNode->InsertEndChild(TiXmlElement("animation"))->ToElement();
1767                        animNode->SetAttribute("name", anim->getName());
1768                        animNode->SetAttribute("length", 
1769                                StringConverter::toString(anim->getLength()));
1770
1771                        TiXmlElement* tracksNode = 
1772                                animNode->InsertEndChild(TiXmlElement("tracks"))->ToElement();
1773                        Animation::VertexTrackIterator iter = anim->getVertexTrackIterator();
1774                        while(iter.hasMoreElements())
1775                        {
1776                                const VertexAnimationTrack* track = iter.getNext();
1777                                TiXmlElement* trackNode = 
1778                                        tracksNode->InsertEndChild(TiXmlElement("track"))->ToElement();
1779
1780                                unsigned short targetID = track->getHandle();
1781                                if (targetID == 0)
1782                                {
1783                                        trackNode->SetAttribute("target", "mesh");
1784                                }
1785                                else
1786                                {
1787                                        trackNode->SetAttribute("target", "submesh");
1788                                        trackNode->SetAttribute("index", 
1789                                                StringConverter::toString(targetID-1));
1790                                }
1791
1792                                if (track->getAnimationType() == VAT_MORPH)
1793                                {
1794                                        trackNode->SetAttribute("type", "morph");
1795                                        writeMorphKeyFrames(trackNode, track);
1796                                }
1797                                else
1798                                {
1799                                        trackNode->SetAttribute("type", "pose");
1800                                        writePoseKeyFrames(trackNode, track);
1801                                }
1802
1803
1804                        }
1805                }
1806
1807               
1808        }
1809        //-----------------------------------------------------------------------------
1810        void XMLMeshSerializer::writeMorphKeyFrames(TiXmlElement* trackNode, const VertexAnimationTrack* track)
1811        {
1812                TiXmlElement* keyframesNode = 
1813                        trackNode->InsertEndChild(TiXmlElement("keyframes"))->ToElement();
1814
1815                size_t vertexCount = track->getAssociatedVertexData()->vertexCount;
1816
1817                for (unsigned short k = 0; k < track->getNumKeyFrames(); ++k)
1818                {
1819                        VertexMorphKeyFrame* kf = track->getVertexMorphKeyFrame(k);
1820                        TiXmlElement* keyNode = 
1821                                keyframesNode->InsertEndChild(TiXmlElement("keyframe"))->ToElement();
1822                        keyNode->SetAttribute("time", 
1823                                StringConverter::toString(kf->getTime()));
1824
1825                        HardwareVertexBufferSharedPtr vbuf = kf->getVertexBuffer();
1826                        float* pFloat = static_cast<float*>(
1827                                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
1828
1829                        for (size_t v = 0; v < vertexCount; ++v)
1830                        {
1831                                TiXmlElement* posNode = 
1832                                        keyNode->InsertEndChild(TiXmlElement("position"))->ToElement();
1833                                posNode->SetAttribute("x", StringConverter::toString(*pFloat++));
1834                                posNode->SetAttribute("y", StringConverter::toString(*pFloat++));
1835                                posNode->SetAttribute("z", StringConverter::toString(*pFloat++));
1836                        }
1837
1838                }
1839        }
1840        //-----------------------------------------------------------------------------
1841        void XMLMeshSerializer::writePoseKeyFrames(TiXmlElement* trackNode, const VertexAnimationTrack* track)
1842        {
1843                TiXmlElement* keyframesNode = 
1844                        trackNode->InsertEndChild(TiXmlElement("keyframes"))->ToElement();
1845
1846                for (unsigned short k = 0; k < track->getNumKeyFrames(); ++k)
1847                {
1848                        VertexPoseKeyFrame* kf = track->getVertexPoseKeyFrame(k);
1849                        TiXmlElement* keyNode = 
1850                                keyframesNode->InsertEndChild(TiXmlElement("keyframe"))->ToElement();
1851                        keyNode->SetAttribute("time", 
1852                                StringConverter::toString(kf->getTime()));
1853
1854                        VertexPoseKeyFrame::PoseRefIterator poseIt = kf->getPoseReferenceIterator();
1855                        while (poseIt.hasMoreElements())
1856                        {
1857                                const VertexPoseKeyFrame::PoseRef& poseRef = poseIt.getNext();
1858                                TiXmlElement* poseRefNode = 
1859                                        keyNode->InsertEndChild(TiXmlElement("poseref"))->ToElement();
1860
1861                                poseRefNode->SetAttribute("poseindex", 
1862                                        StringConverter::toString(poseRef.poseIndex));
1863                                poseRefNode->SetAttribute("influence", 
1864                                        StringConverter::toString(poseRef.influence));
1865
1866                        }
1867
1868                }
1869
1870
1871        }
1872
1873
1874
1875
1876}
1877
Note: See TracBrowser for help on using the repository browser.