Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/Tools/MayaExport/src/mesh.cpp @ 50

Last change on this file since 50 was 6, checked in by anonymous, 18 years ago

=…

File size: 46.7 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// mesh.cpp
3// Author     : Francesco Giordana
4// Start Date : January 13, 2005
5// Copyright  : (C) 2006 by Francesco Giordana
6// Email      : fra.giordana@tiscali.it
7////////////////////////////////////////////////////////////////////////////////
8
9/*********************************************************************************
10*                                                                                *
11*   This program is free software; you can redistribute it and/or modify         *
12*   it under the terms of the GNU Lesser General Public License as published by  *
13*   the Free Software Foundation; either version 2 of the License, or            *
14*   (at your option) any later version.                                          *
15*                                                                                *
16**********************************************************************************/
17
18#include "mesh.h"
19#include <maya/MFnMatrixData.h>
20
21namespace OgreMayaExporter
22{
23        /***** Class Mesh *****/
24        // constructor
25        Mesh::Mesh(const MString& name)
26        {
27                m_name = name;
28                m_numTriangles = 0;
29                m_pSkeleton = NULL;
30                m_sharedGeom.vertices.clear();
31                m_sharedGeom.dagMap.clear();
32                m_vertexClips.clear();
33                m_BSClips.clear();
34        }
35
36        // destructor
37        Mesh::~Mesh()
38        {
39                clear();
40        }
41
42        // clear data
43        void Mesh::clear()
44        {
45                int i;
46                m_name = "";
47                m_numTriangles = 0;
48                for (i=0; i<m_submeshes.size(); i++)
49                        delete m_submeshes[i];
50                for (i=0; i<m_sharedGeom.dagMap.size(); i++)
51                {
52                        if (m_sharedGeom.dagMap[i].pBlendShape)
53                                delete m_sharedGeom.dagMap[i].pBlendShape;
54                }
55                m_sharedGeom.vertices.clear();
56                m_sharedGeom.dagMap.clear();
57                m_vertexClips.clear();
58                m_BSClips.clear();
59                m_uvsets.clear();
60                m_submeshes.clear();
61                if (m_pSkeleton)
62                        delete m_pSkeleton;
63                m_pSkeleton = NULL;
64        }
65
66        // get pointer to linked skeleton
67        Skeleton* Mesh::getSkeleton()
68        {
69                return m_pSkeleton;
70        }
71
72        /*******************************************************************************
73         *                    Load mesh data from a Maya node                          *
74         *******************************************************************************/
75        MStatus Mesh::load(const MDagPath& meshDag,ParamList &params)
76        {
77                MStatus stat;
78                // Check that given DagPath corresponds to a mesh node
79                if (!meshDag.hasFn(MFn::kMesh))
80                        return MS::kFailure;
81
82                // Set mesh name
83                m_name = "mayaExport";
84
85                // Initialise temporary variables
86                newvertices.clear();
87                newweights.clear();
88                newjointIds.clear();
89                newuvsets.clear();
90                newpoints.clear();
91                newnormals.clear();
92                params.currentRootJoints.clear();
93                opposite = false;
94                shaders.clear();
95                shaderPolygonMapping.clear();
96                polygonSets.clear();
97                pSkinCluster = NULL;
98                pBlendShape = NULL;
99
100                // Get mesh uvsets
101                stat = getUVSets(meshDag);             
102                if (stat != MS::kSuccess)
103                {
104                        std::cout << "Error retrieving uvsets for current mesh\n";
105                        std::cout.flush();
106                }
107                // Get linked skin cluster
108                stat = getSkinCluster(meshDag,params);
109                if (stat != MS::kSuccess)
110                {
111                        std::cout << "Error retrieving skin cluster linked to current mesh\n";
112                        std::cout.flush();
113                }
114                // Get linked blend shape deformer
115                stat = getBlendShapeDeformer(meshDag,params);
116                if (stat != MS::kSuccess)
117                {
118                        std::cout << "Error retrieving blend shape deformer linked to current mesh\n";
119                        std::cout.flush();
120                }
121                // Get connected shaders
122                stat = getShaders(meshDag);
123                if (stat != MS::kSuccess)
124                {
125                        std::cout << "Error getting shaders connected to current mesh\n";
126                        std::cout.flush();
127                }
128                // Get vertex data
129                stat = getVertices(meshDag,params);
130                if (stat != MS::kSuccess)
131                {
132                        std::cout << "Error retrieving vertex data for current mesh\n";
133                        std::cout.flush();
134                }
135                // Get vertex bone weights
136                if (pSkinCluster)
137                {
138                        getVertexBoneWeights(meshDag,params);
139                        if (stat != MS::kSuccess)
140                        {
141                                std::cout << "Error retrieving veretex bone assignements for current mesh\n";
142                                std::cout.flush();
143                        }
144                }
145                // Get faces data
146                stat = getFaces(meshDag,params);
147                if (stat != MS::kSuccess)
148                {
149                        std::cout << "Error retrieving faces data for current mesh\n";
150                        std::cout.flush();
151                }
152                // Build shared geometry
153                if (params.useSharedGeom)
154                {
155                        stat = buildSharedGeometry(meshDag,params);
156                        if (stat != MS::kSuccess)
157                        {
158                                std::cout << "Error building shared geometry for current mesh\n";
159                                std::cout.flush();
160                        }
161                }
162                // Create submeshes (a different submesh for every different shader linked to the mesh)
163                stat = createSubmeshes(meshDag,params);
164                if (stat != MS::kSuccess)
165                {
166                        std::cout << "Error creating submeshes for current mesh\n";
167                        std::cout.flush();
168                }
169                // Free up memory
170                newvertices.clear();
171                newweights.clear();
172                newjointIds.clear();
173                newpoints.clear();
174                newnormals.clear();
175                newuvsets.clear();
176                shaders.clear();
177                shaderPolygonMapping.clear();
178                polygonSets.clear();
179                if (pSkinCluster)
180                        delete pSkinCluster;
181                pBlendShape = NULL;
182
183                return MS::kSuccess;
184        }
185
186
187        /*******************************************************************************
188         *                    Load mesh animations from Maya                           *
189         *******************************************************************************/
190        // Load vertex animations
191        MStatus Mesh::loadAnims(ParamList& params)
192        {
193                MStatus stat;
194                int i;
195                // save current time for later restore
196                MTime curTime = MAnimControl::currentTime();
197                std::cout << "Loading vertex animations...\n";
198                std::cout.flush();
199                // clear animations data
200                m_vertexClips.clear();
201                // load the requested clips
202                for (i=0; i<params.vertClipList.size(); i++)
203                {
204                        std::cout << "Loading clip " << params.vertClipList[i].name.asChar() << "\n";
205                        std::cout.flush();
206                        stat = loadClip(params.vertClipList[i].name,params.vertClipList[i].start,
207                                params.vertClipList[i].stop,params.vertClipList[i].rate,params);
208                        if (stat == MS::kSuccess)
209                        {
210                                std::cout << "Clip successfully loaded\n";
211                                std::cout.flush();
212                        }
213                        else
214                        {
215                                std::cout << "Failed loading clip\n";
216                                std::cout.flush();
217                        }
218                }
219                //restore current time
220                MAnimControl::setCurrentTime(curTime);
221                return MS::kSuccess;
222        }
223
224
225
226        // Load blend shape deformers
227        MStatus Mesh::loadBlendShapes(ParamList &params)
228        {
229                MStatus stat;
230                int i;
231                std::cout << "Loading blend shape poses...\n";
232                std::cout.flush();
233                // Set envelopes of all blend shape deformers to 0
234                if (params.useSharedGeom)
235                {
236                        for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
237                        {
238                                dagInfo di = m_sharedGeom.dagMap[i];
239                                if (di.pBlendShape)
240                                        di.pBlendShape->setEnvelope(0);
241                        }
242                }
243                else
244                {
245                        for (i=0; i<m_submeshes.size(); i++)
246                        {
247                                Submesh* pSubmesh = m_submeshes[i];
248                                if (pSubmesh->m_pBlendShape)
249                                        pSubmesh->m_pBlendShape->setEnvelope(0);
250                        }
251                }
252                // Get the blend shape poses
253                if (params.useSharedGeom)
254                {
255                        for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
256                        {
257                                dagInfo di = m_sharedGeom.dagMap[i];
258                                if (di.pBlendShape)
259                                        di.pBlendShape->loadPoses(di.dagPath,params,m_sharedGeom.vertices,di.numVertices,di.offset);
260                        }
261                }
262                else
263                {
264                        for (i=0; i<m_submeshes.size(); i++)
265                        {
266                                Submesh* pSubmesh = m_submeshes[i];
267                                if (pSubmesh->m_pBlendShape)
268                                        pSubmesh->m_pBlendShape->loadPoses(pSubmesh->m_dagPath,params,pSubmesh->m_vertices,
269                                                pSubmesh->m_vertices.size(),0,i);
270                        }
271                }
272                // Restore blend shape deformers original envelopes
273                if (params.useSharedGeom)
274                {
275                        for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
276                        {
277                                dagInfo di = m_sharedGeom.dagMap[i];
278                                if (di.pBlendShape)
279                                        di.pBlendShape->restoreEnvelope();
280                        }
281                }
282                else
283                {
284                        for (i=0; i<m_submeshes.size(); i++)
285                        {
286                                Submesh* pSubmesh = m_submeshes[i];
287                                if (pSubmesh->m_pBlendShape)
288                                        pSubmesh->m_pBlendShape->restoreEnvelope();
289                        }
290                }
291                // Read blend shape animations
292                if (params.exportBSAnims)
293                {
294                        stat = loadBlendShapeAnimations(params);
295                }
296                return MS::kSuccess;
297        }
298
299        // Load blend shape animations
300        MStatus Mesh::loadBlendShapeAnimations(ParamList& params)
301        {
302                int i,j,k;
303                std::cout << "Loading blend shape animations...\n";
304                std::cout.flush();
305                // Read the list of blend shape clips to export
306                for (i=0; i<params.BSClipList.size(); i++)
307                {
308                        int startPoseId = 0;
309                        clipInfo ci = params.BSClipList[i];
310                        // Create a new animation for every clip
311                        Animation a;
312                        a.m_name = ci.name;
313                        a.m_length = ci.stop - ci.start;
314                        a.m_tracks.clear();
315                        std::cout << "clip " << ci.name.asChar() << "\n";
316                        // Read animation tracks from the blend shape deformer
317                        if (params.useSharedGeom)
318                        {
319                                // Create a track for each blend shape
320                                std::vector<Track> tracks;
321                                for  (j=0; j<m_sharedGeom.dagMap.size(); j++)
322                                {
323                                        dagInfo di = m_sharedGeom.dagMap[j];
324                                        if (di.pBlendShape)
325                                        {
326                                                Track t = di.pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId);
327                                                tracks.push_back(t);
328                                                startPoseId += di.pBlendShape->getPoses().size();
329                                        }
330                                }
331                                // Merge the tracks into a single track (shared geometry must have a single animation track)
332                                if (tracks.size() > 0)
333                                {
334                                        Track newTrack;
335                                        // Merge keyframes at the same time position from all tracks
336                                        for (j=0; j<tracks[0].m_vertexKeyframes.size(); j++)
337                                        {
338                                                // Create a new keyframe
339                                                vertexKeyframe newKeyframe;
340                                                newKeyframe.time = tracks[0].m_vertexKeyframes[j].time;
341                                                // Get keyframe at current position from all tracks
342                                                for (k=0; k<tracks.size(); k++)
343                                                {
344                                                        vertexKeyframe* pSrcKeyframe = &tracks[k].m_vertexKeyframes[j];
345                                                        int pri;
346                                                        // Add pose references from this keyframe to the new keyframe for the joined track
347                                                        for (pri=0; pri<pSrcKeyframe->poserefs.size(); pri++)
348                                                        {
349                                                                // Create a new pose reference
350                                                                vertexPoseRef poseref;
351                                                                // Copy pose reference settings from source keyframe
352                                                                poseref.poseIndex = pSrcKeyframe->poserefs[pri].poseIndex;
353                                                                poseref.poseWeight = pSrcKeyframe->poserefs[pri].poseWeight;
354                                                                // Add the new pose reference to the new keyframe
355                                                                newKeyframe.poserefs.push_back(poseref);
356                                                        }
357                                                }
358                                                // Add the keyframe to the new joined track
359                                                newTrack.m_vertexKeyframes.push_back(newKeyframe);
360                                        }
361                                        // Add the joined track to current animation clip
362                                        a.addTrack(newTrack);
363                                }
364                        }
365                        else
366                        {
367                                // Create a track for each submesh
368                                std::vector<Track> tracks;
369                                for (j=0; j<m_submeshes.size(); j++)
370                                {
371                                        Submesh* pSubmesh = m_submeshes[j];
372                                        if (pSubmesh->m_pBlendShape)
373                                        {
374                                                Track t = pSubmesh->m_pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId);
375                                                a.addTrack(t);
376                                                startPoseId += pSubmesh->m_pBlendShape->getPoses().size();
377                                        }
378                                }
379                        }
380                        std::cout << "length: " << a.m_length << "\n";
381                        std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n";
382                        std::cout.flush();
383                        m_BSClips.push_back(a);
384                }
385                return MS::kSuccess;
386        }
387/******************** Methods to parse geometry data from Maya ************************/
388        // Get uvsets info from the maya mesh
389        MStatus Mesh::getUVSets(const MDagPath& meshDag)
390        {
391                MFnMesh mesh(meshDag);
392                int i;
393                MStatus stat;
394                // Get uv texture coordinate sets' names
395                if (mesh.numUVSets() > 0)
396                {
397                        stat = mesh.getUVSetNames(newuvsets);
398                        if (MS::kSuccess != stat)
399                        {
400                                std::cout << "Error retrieving UV sets names\n";
401                                std::cout.flush();
402                                return MS::kFailure;
403                        }
404                }
405                // Save uvsets info
406                for (i=m_uvsets.size(); i<newuvsets.length(); i++)
407                {
408                        uvset uv;
409                        uv.size = 2;
410                        m_uvsets.push_back(uv);
411                }
412                return MS::kSuccess;
413        }
414
415
416        // Get skin cluster linked to the maya mesh
417        MStatus Mesh::getSkinCluster(const MDagPath &meshDag, ParamList &params)
418        {
419                MStatus stat;
420                MFnMesh mesh(meshDag);
421                pSkinCluster = NULL;
422                if (params.exportVBA || params.exportSkeleton)
423                {
424                        // get connected skin clusters (if present)
425                        MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter );           
426                        for( ;!kDepNodeIt.isDone() && !pSkinCluster; kDepNodeIt.next()) 
427                        {           
428                                MObject kObject = kDepNodeIt.item();
429                                pSkinCluster = new MFnSkinCluster(kObject);
430                                unsigned int uiNumGeometries = pSkinCluster->numOutputConnections();
431                                unsigned int uiGeometry;
432                                for(uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) 
433                                {
434                                        unsigned int uiIndex = pSkinCluster->indexForOutputConnection(uiGeometry);
435                                        MObject kOutputObject = pSkinCluster->outputShapeAtIndex(uiIndex);
436                                        if(kOutputObject == mesh.object()) 
437                                        {
438                                                std::cout << "Found skin cluster " << pSkinCluster->name().asChar() << " for mesh " 
439                                                        << mesh.name().asChar() << "\n"; 
440                                                std::cout.flush();
441                                        }       
442                                        else
443                                        {
444                                                delete pSkinCluster;
445                                                pSkinCluster = NULL;
446                                        }
447                                }
448                        }
449                        if (pSkinCluster)
450                        {
451                                // load the skeleton
452                                std::cout << "Loading skeleton data...\n";
453                                std::cout.flush();
454                                if (!m_pSkeleton)
455                                        m_pSkeleton = new Skeleton();
456                                stat = m_pSkeleton->load(pSkinCluster,params);
457                                if (MS::kSuccess != stat)
458                                {
459                                        std::cout << "Error loading skeleton data\n";
460                                        std::cout.flush();
461                                }
462                                else
463                                {
464                                        std::cout << "OK\n";
465                                        std::cout.flush();
466                                }
467                        }
468                }
469                return MS::kSuccess;
470        }
471
472
473        // Get blend shape deformer linked to the maya mesh
474        MStatus Mesh::getBlendShapeDeformer(const MDagPath &meshDag, OgreMayaExporter::ParamList &params)
475        {
476                MStatus stat;
477                MFnMesh mesh(meshDag);
478                if (params.exportBlendShapes)
479                {
480                        // get connected blend shape deformer (if present)
481                        MItDependencyNodes kDepNodeIt( MFn::kBlendShape );           
482                        for( ;!kDepNodeIt.isDone() && !pBlendShape; kDepNodeIt.next()) 
483                        {   
484                                MObject kObject = kDepNodeIt.item();
485                                MItDependencyGraph itGraph(kObject,MFn::kMesh,MItDependencyGraph::kDownstream,MItDependencyGraph::kDepthFirst);
486                                for (;!itGraph.isDone() && !pBlendShape; itGraph.next())
487                                {
488                                        MFnMesh connectedMesh(itGraph.thisNode());
489                                        if (connectedMesh.fullPathName() == mesh.fullPathName())
490                                        {
491                                                pBlendShape = new BlendShape();
492                                                pBlendShape->load(kObject);
493                                                std::cout << "Found blend shape deformer " << pBlendShape->getName().asChar() << " for mesh " 
494                                                        << mesh.name().asChar() << "\n"; 
495                                        }       
496                                }
497                        }
498                }
499                return MS::kSuccess;
500        }
501        // Get connected shaders
502        MStatus Mesh::getShaders(const MDagPath& meshDag)
503        {
504                MStatus stat;
505                MFnMesh mesh(meshDag);
506                stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping);
507                std::cout.flush();
508                if (MS::kSuccess != stat)
509                {
510                        std::cout << "Error getting connected shaders\n";
511                        std::cout.flush();
512                        return MS::kFailure;
513                }
514                std::cout << "Found " << shaders.length() << " connected shaders\n";
515                std::cout.flush();
516                if (shaders.length() <= 0)
517                {
518                        std::cout << "No connected shaders, skipping mesh\n";
519                        std::cout.flush();
520                        return MS::kFailure;
521                }
522                // create a series of arrays of faces for each different submesh
523                polygonSets.clear();
524                polygonSets.resize(shaders.length());
525                return MS::kSuccess;
526        }
527
528
529        // Get vertex data
530        MStatus Mesh::getVertices(const MDagPath &meshDag, OgreMayaExporter::ParamList &params)
531        {
532                int i;
533                MFnMesh mesh(meshDag);
534                // prepare vertex table
535                newvertices.resize(mesh.numVertices());
536                newweights.resize(mesh.numVertices());
537                newjointIds.resize(mesh.numVertices());
538                for (i=0; i<newvertices.size(); i++)
539                {
540                        newvertices[i].pointIdx = -1;
541                        newvertices[i].normalIdx = -1;
542                        newvertices[i].next = -2;
543                }
544                //get vertex positions from mesh
545                if (params.exportWorldCoords || (pSkinCluster && params.exportSkeleton))
546                        mesh.getPoints(newpoints,MSpace::kWorld);
547                else
548                        mesh.getPoints(newpoints,MSpace::kTransform);
549                //get list of normals from mesh data
550                if (params.exportWorldCoords)
551                        mesh.getNormals(newnormals,MSpace::kWorld);
552                else
553                        mesh.getNormals(newnormals,MSpace::kTransform);
554                //check the "opposite" attribute to see if we have to flip normals
555                mesh.findPlug("opposite",true).getValue(opposite);
556                return MS::kSuccess;
557        }
558
559
560        // Get vertex bone assignements
561        MStatus Mesh::getVertexBoneWeights(const MDagPath& meshDag, OgreMayaExporter::ParamList &params)
562        {
563                int i,j,k;
564                unsigned int numWeights;
565                MStatus stat;
566                std::cout << "Get vbas\n";
567                std::cout.flush();
568                MItGeometry iterGeom(meshDag);
569                for (i=0; !iterGeom.isDone(); iterGeom.next(), i++)
570                {
571                        MObject component = iterGeom.component();
572                        MFloatArray vertexWeights;
573                        stat=pSkinCluster->getWeights(meshDag,component,vertexWeights,numWeights);
574        /*              //normalize vertex weights
575                        int widx;
576                        // first, truncate the weights to given precision
577                        long weightSum = 0;
578                        for (widx=0; widx < vertexWeights.length(); widx++)
579                        {
580                                long w = (long) (((float)vertexWeights[widx]) / ((float)PRECISION));
581                                vertexWeights[widx] = w;
582                                weightSum += w;
583                        }
584                        // then divide by the sum of the weights to add up to 1
585                        // (if there is at least one weight > 0)
586                        if (weightSum > 0)
587                        {
588                                float newSum = 0;
589                                for (widx=0; widx < numWeights; widx++)
590                                {
591                                        long w = (long) ((float)vertexWeights[widx] / ((float)PRECISION));
592                                        w = (long) (((float)w) / ((float)weightSum));
593                                        vertexWeights[widx] = (float) (((long)w) * ((float)PRECISION));
594                                        newSum += vertexWeights[widx];
595                                }
596                                if (newSum < 1.0f)
597                                        vertexWeights[numWeights-1] += PRECISION;
598                        }
599                        // else set all weights to 0
600                        else
601                        {
602                                for (widx=0; widx < numWeights; widx++)
603                                        vertexWeights[widx] = 0;
604                        }*/
605                        // save the normalized weights
606                        newweights[i]=vertexWeights;
607                        if (MS::kSuccess != stat)
608                        {
609                                std::cout << "Error retrieving vertex weights\n";
610                                std::cout.flush();
611                        }
612                        // get ids for the joints
613                        if (m_pSkeleton)
614                        {
615                                MDagPathArray influenceObjs;
616                                pSkinCluster->influenceObjects(influenceObjs,&stat);
617                                if (MS::kSuccess != stat)
618                                {
619                                        std::cout << "Error retrieving influence objects for given skin cluster\n";
620                                        std::cout.flush();
621                                }
622                                newjointIds[i].setLength(newweights[i].length());
623                                for (j=0; j<influenceObjs.length(); j++)
624                                {
625                                        bool foundJoint = false;
626                                        MString partialPathName = influenceObjs[j].partialPathName(); 
627                                        for (k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++)
628                                        {
629                                                if (partialPathName == m_pSkeleton->getJoints()[k].name)
630                                                {
631                                                        foundJoint=true;
632                                                        newjointIds[i][j] = m_pSkeleton->getJoints()[k].id;
633                                                }
634                                        }
635                                }
636                        }
637                }
638                return MS::kSuccess;
639        }
640
641
642        // Get faces data
643        MStatus Mesh::getFaces(const MDagPath &meshDag, ParamList &params)
644        {
645                int i,j,k;
646                MStatus stat;
647                MFnMesh mesh(meshDag);
648                // create an iterator to go through mesh polygons
649                if (mesh.numPolygons() > 0)
650                {
651                        std::cout << "Iterate over mesh polygons\n";
652                        std::cout.flush();
653                        MItMeshPolygon faceIter(mesh.object(),&stat);
654                        if (MS::kSuccess != stat)
655                        {
656                                std::cout << "Error accessing mesh polygons\n";
657                                std::cout.flush();
658                                return MS::kFailure;
659                        }
660                        std::cout << "num polygons = " << mesh.numPolygons() << "\n";
661                        std::cout.flush();
662                        // iterate over mesh polygons
663                        for (; !faceIter.isDone(); faceIter.next())
664                        {
665                                int numTris=0;
666                                int iTris;
667                                bool different;
668                                int vtxIdx, nrmIdx;
669                                faceIter.numTriangles(numTris);
670                                // for every triangle composing current polygon extract triangle info
671                                for (iTris=0; iTris<numTris; iTris++)
672                                {
673                                        MPointArray triPoints;
674                                        MIntArray tempTriVertexIdx,triVertexIdx;
675                                        int idx;
676                                        // create a new face to store triangle info
677                                        face newFace;
678                                        // extract triangle vertex indices
679                                        faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx);
680                                        // convert indices to face-relative indices
681                                        MIntArray polyIndices;
682                                        faceIter.getVertices(polyIndices);
683                                        unsigned int iPoly, iObj;
684                                        for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj)
685                                        {
686                                                // iPoly is face-relative vertex index
687                                                for (iPoly=0; iPoly < polyIndices.length(); ++iPoly)
688                                                {
689                                                        if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) 
690                                                        {
691                                                                triVertexIdx.append(iPoly);
692                                                                break;
693                                                        }
694                                                }
695                                        }
696                                        // iterate over triangle's vertices
697                                        for (i=0; i<3; i++)
698                                        {
699                                                different = true;
700                                                vtxIdx = faceIter.vertexIndex(triVertexIdx[i],&stat);
701                                                if (stat != MS::kSuccess)
702                                                {
703                                                        std::cout << "Could not access vertex position\n";
704                                                        std::cout.flush();
705                                                }
706                                                nrmIdx = faceIter.normalIndex(triVertexIdx[i],&stat);
707                                                if (stat != MS::kSuccess)
708                                                {
709                                                        std::cout << "Could not access vertex normal\n";
710                                                        std::cout.flush();
711                                                }
712
713                                                // get vertex color
714                                                MColor color;
715                                                if (faceIter.hasColor(triVertexIdx[i]))
716                                                {
717                                                        stat = faceIter.getColor(color,triVertexIdx[i]);
718                                                        if (MS::kSuccess != stat)
719                                                        {
720                                                                color = MColor(1,1,1,1);
721                                                        }
722                                                        if (color.r > 1)
723                                                                color.r = 1;
724                                                        else if (color.r < PRECISION)
725                                                                color.r = 0;
726                                                        if (color.g > 1)
727                                                                color.g = 1;
728                                                        else if (color.g < PRECISION)
729                                                                color.g = 0;
730                                                        if (color.b > 1)
731                                                                color.b = 1;
732                                                        else if (color.b < PRECISION)
733                                                                color.b = 0;
734                                                        if (color.a > 1)
735                                                                color.a = 1;
736                                                        else if (color.a < PRECISION)
737                                                                color.a = 0;
738                                                }
739                                                else
740                                                {
741                                                        color = MColor(1,1,1,1);
742                                                }
743                                                if (newvertices[vtxIdx].next == -2)     // first time we encounter a vertex in this position
744                                                {
745                                                        // save vertex position
746                                                        newpoints[vtxIdx].cartesianize();
747                                                        newvertices[vtxIdx].pointIdx = vtxIdx;
748                                                        // save vertex normal
749                                                        newvertices[vtxIdx].normalIdx = nrmIdx;
750                                                        // save vertex colour
751                                                        newvertices[vtxIdx].r = color.r;
752                                                        newvertices[vtxIdx].g = color.g;
753                                                        newvertices[vtxIdx].b = color.b;
754                                                        newvertices[vtxIdx].a = color.a;
755                                                        // save vertex texture coordinates
756                                                        newvertices[vtxIdx].u.resize(newuvsets.length());
757                                                        newvertices[vtxIdx].v.resize(newuvsets.length());
758                                                        // save vbas
759                                                        newvertices[vtxIdx].vba.resize(newweights[vtxIdx].length());
760                                                        for (j=0; j<newweights[vtxIdx].length(); j++)
761                                                        {
762                                                                newvertices[vtxIdx].vba[j] = (newweights[vtxIdx])[j];
763                                                        }
764                                                        // save joint ids
765                                                        newvertices[vtxIdx].jointIds.resize(newjointIds[vtxIdx].length());
766                                                        for (j=0; j<newjointIds[vtxIdx].length(); j++)
767                                                        {
768                                                                newvertices[vtxIdx].jointIds[j] = (newjointIds[vtxIdx])[j];
769                                                        }
770                                                        // save uv sets data
771                                                        for (j=0; j<newuvsets.length(); j++)
772                                                        {
773                                                                float2 uv;
774                                                                stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
775                                                                if (MS::kSuccess != stat)
776                                                                {
777                                                                        uv[0] = 0;
778                                                                        uv[1] = 0;
779                                                                }
780                                                                newvertices[vtxIdx].u[j] = uv[0];
781                                                                newvertices[vtxIdx].v[j] = (-1)*(uv[1]-1);
782                                                        }
783                                                        // save vertex index in face info
784                                                        newFace.v[i] = m_sharedGeom.vertices.size() + vtxIdx;
785                                                        // update value of index to next vertex info (-1 means nothing next)
786                                                        newvertices[vtxIdx].next = -1;
787                                                }
788                                                else    // already found at least 1 vertex in this position
789                                                {
790                                                        // check if a vertex with same attributes has been saved already
791                                                        for (k=vtxIdx; k!=-1 && different; k=newvertices[k].next)
792                                                        {
793                                                                different = false;
794
795                                                                if (params.exportVertNorm)
796                                                                {
797                                                                        MFloatVector n1 = newnormals[newvertices[k].normalIdx];
798                                                                        MFloatVector n2 = newnormals[nrmIdx];
799                                                                        if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z)
800                                                                        {
801                                                                                different = true;
802                                                                        }
803                                                                }
804
805                                                                if ((params.exportVertCol) &&
806                                                                        (newvertices[k].r!=color.r || newvertices[k].g!=color.g || newvertices[k].b!= color.b || newvertices[k].a!=color.a))
807                                                                {
808                                                                        different = true;
809                                                                }
810
811                                                                if (params.exportTexCoord)
812                                                                {
813                                                                        for (j=0; j<newuvsets.length(); j++)
814                                                                        {
815                                                                                float2 uv;
816                                                                                stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
817                                                                                if (MS::kSuccess != stat)
818                                                                                {
819                                                                                        uv[0] = 0;
820                                                                                        uv[1] = 0;
821                                                                                }
822                                                                                uv[1] = (-1)*(uv[1]-1);
823                                                                                if (newvertices[k].u[j]!=uv[0] || newvertices[k].v[j]!=uv[1])
824                                                                                {
825                                                                                        different = true;
826                                                                                }
827                                                                        }
828                                                                }
829
830                                                                idx = k;
831                                                        }
832                                                        // if no identical vertex has been saved, then save the vertex info
833                                                        if (different)
834                                                        {
835                                                                vertexInfo vtx;
836                                                                // save vertex position
837                                                                vtx.pointIdx = vtxIdx;
838                                                                // save vertex normal
839                                                                vtx.normalIdx = nrmIdx;
840                                                                // save vertex colour
841                                                                vtx.r = color.r;
842                                                                vtx.g = color.g;
843                                                                vtx.b = color.b;
844                                                                vtx.a = color.a;
845                                                                // save vertex vba
846                                                                vtx.vba.resize(newweights[vtxIdx].length());
847                                                                for (j=0; j<newweights[vtxIdx].length(); j++)
848                                                                {
849                                                                        vtx.vba[j] = (newweights[vtxIdx])[j];
850                                                                }
851                                                                // save joint ids
852                                                                vtx.jointIds.resize(newjointIds[vtxIdx].length());
853                                                                for (j=0; j<newjointIds[vtxIdx].length(); j++)
854                                                                {
855                                                                        vtx.jointIds[j] = (newjointIds[vtxIdx])[j];
856                                                                }
857                                                                // save vertex texture coordinates
858                                                                vtx.u.resize(newuvsets.length());
859                                                                vtx.v.resize(newuvsets.length());
860                                                                for (j=0; j<newuvsets.length(); j++)
861                                                                {
862                                                                        float2 uv;
863                                                                        stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
864                                                                        if (MS::kSuccess != stat)
865                                                                        {
866                                                                                uv[0] = 0;
867                                                                                uv[1] = 0;
868                                                                        }
869                                                                        if (fabs(uv[0]) < PRECISION)
870                                                                                uv[0] = 0;
871                                                                        if (fabs(uv[1]) < PRECISION)
872                                                                                uv[1] = 0;
873                                                                        vtx.u[j] = uv[0];
874                                                                        vtx.v[j] = (-1)*(uv[1]-1);
875                                                                }
876                                                                vtx.next = -1;
877                                                                newvertices.push_back(vtx);
878                                                                // save vertex index in face info
879                                                                newFace.v[i] = m_sharedGeom.vertices.size() + newvertices.size()-1;
880                                                                newvertices[idx].next = newvertices.size()-1;
881                                                        }
882                                                        else
883                                                        {
884                                                                newFace.v[i] = m_sharedGeom.vertices.size() + idx;
885                                                        }
886                                                }
887                                        } // end iteration of triangle vertices
888                                        // add face info to the array corresponding to the submesh it belongs
889                                        // skip faces with no shaders assigned
890                                        if (shaderPolygonMapping[faceIter.index()] >= 0)
891                                                polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace);
892                                } // end iteration of triangles
893                        }
894                }
895                std::cout << "done reading mesh triangles\n";
896                std::cout.flush();
897                return MS::kSuccess;
898        }
899
900
901        // Build shared geometry
902        MStatus Mesh::buildSharedGeometry(const MDagPath &meshDag,ParamList& params)
903        {
904                int i,j,k;
905                std::cout << "Create list of shared vertices\n";
906                std::cout.flush();
907                // save a new entry in the shared geometry map: we associate the index of the first
908                // vertex we're loading with the dag path from which it has been read
909                dagInfo di;
910                di.offset = m_sharedGeom.vertices.size();
911                di.dagPath = meshDag;
912                di.pBlendShape = pBlendShape;
913                // load shared vertices
914                for (i=0; i<newvertices.size(); i++)
915                {
916                        vertex v;
917                        vertexInfo vInfo = newvertices[i];
918                        // save vertex coordinates (rescale to desired length unit)
919                        MPoint point = newpoints[vInfo.pointIdx] * params.lum;
920                        if (fabs(point.x) < PRECISION)
921                                point.x = 0;
922                        if (fabs(point.y) < PRECISION)
923                                point.y = 0;
924                        if (fabs(point.z) < PRECISION)
925                                point.z = 0;
926                        v.x = point.x;
927                        v.y = point.y;
928                        v.z = point.z;
929                        // save vertex normal
930                        MFloatVector normal = newnormals[vInfo.normalIdx];
931                        if (fabs(normal.x) < PRECISION)
932                                normal.x = 0;
933                        if (fabs(normal.y) < PRECISION)
934                                normal.y = 0;
935                        if (fabs(normal.z) < PRECISION)
936                                normal.z = 0;
937                        if (opposite)
938                        {
939                                v.n.x = -normal.x;
940                                v.n.y = -normal.y;
941                                v.n.z = -normal.z;
942                        }
943                        else
944                        {
945                                v.n.x = normal.x;
946                                v.n.y = normal.y;
947                                v.n.z = normal.z;
948                        }
949                        v.n.normalize();
950                        // save vertex color
951                        v.r = vInfo.r;
952                        v.g = vInfo.g;
953                        v.b = vInfo.b;
954                        v.a = vInfo.a;
955                        // save vertex bone assignements
956                        for (k=0; k<vInfo.vba.size(); k++)
957                        {
958                                vba newVba;
959                                newVba.jointIdx = vInfo.jointIds[k];
960                                newVba.weight = vInfo.vba[k];
961                                v.vbas.push_back(newVba);
962                        }
963                        // save texture coordinates
964                        for (k=0; k<vInfo.u.size(); k++)
965                        {
966                                texcoords newTexCoords;
967                                newTexCoords.u = vInfo.u[k];
968                                newTexCoords.v = vInfo.v[k];
969                                newTexCoords.w = 0;
970                                v.texcoords.push_back(newTexCoords);
971                        }
972                        // save vertex index in maya mesh, to retrieve future positions of the same vertex
973                        v.index = vInfo.pointIdx;
974                        // add newly created vertex to vertices list
975                        m_sharedGeom.vertices.push_back(v);
976                }
977                // Make sure all vertices have the same number of texture coordinates
978                for (i=0; i<m_sharedGeom.vertices.size(); i++)
979                {
980                        vertex* pV = &m_sharedGeom.vertices[i];
981                        for (j=pV->texcoords.size(); j<m_uvsets.size(); j++)
982                        {
983                                texcoords newTexCoords;
984                                newTexCoords.u = 0;
985                                newTexCoords.v = 0;
986                                newTexCoords.w = 0;
987                                pV->texcoords.push_back(newTexCoords);
988                        }
989                }
990                // save number of vertices referring to this mesh dag in the dag path map
991                di.numVertices = m_sharedGeom.vertices.size() - di.offset;
992                m_sharedGeom.dagMap.push_back(di);
993                std::cout << "done creating vertices list\n";
994                std::cout.flush();
995                return MS::kSuccess;
996        }
997
998
999        // Create submeshes
1000        MStatus Mesh::createSubmeshes(const MDagPath& meshDag,ParamList& params)
1001        {
1002                int i;
1003                MStatus stat;
1004                MFnMesh mesh(meshDag);
1005                for (i=0; i<shaders.length(); i++)
1006                {
1007                        // check if the submesh has at least 1 triangle
1008                        if (polygonSets[i].size() > 0)
1009                        {
1010                                //create new submesh
1011                                Submesh* pSubmesh = new Submesh();
1012                                //load linked shader
1013                                stat = pSubmesh->loadMaterial(shaders[i],newuvsets,params);
1014                                if (stat != MS::kSuccess)
1015                                {
1016                                        MFnDependencyNode shadingGroup(shaders[i]);
1017                                        std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n";
1018                                        std::cout.flush();
1019                                        return MS::kFailure;
1020                                }
1021                                //load vertex and face data
1022                                stat = pSubmesh->load(meshDag,polygonSets[i],newvertices,newpoints,newnormals,newuvsets,params,opposite);
1023                                //if we're not using shared geometry, save a pointer to the blend shape deformer
1024                                if (pBlendShape && !params.useSharedGeom)
1025                                        pSubmesh->m_pBlendShape = pBlendShape;
1026                                //add submesh to current mesh
1027                                m_submeshes.push_back(pSubmesh);
1028                                //update number of triangles composing the mesh
1029                                m_numTriangles += pSubmesh->numTriangles();
1030                        }
1031                }
1032                return MS::kSuccess;
1033        }
1034
1035
1036
1037
1038
1039/******************** Methods to read vertex animations from Maya ************************/
1040        //load a vertex animation clip
1041        MStatus Mesh::loadClip(MString& clipName,float start,float stop,float rate,ParamList& params)
1042        {
1043                MStatus stat;
1044                MString msg;
1045                std::vector<float> times;
1046                // calculate times from clip sample rate
1047                times.clear();
1048                for (float t=start; t<stop; t+=rate)
1049                        times.push_back(t);
1050                times.push_back(stop);
1051                // get animation length
1052                float length=0;
1053                if (times.size() >= 0)
1054                        length = times[times.size()-1] - times[0];
1055                if (length < 0)
1056                {
1057                        std::cout << "invalid time range for the clip, we skip it\n";
1058                        std::cout.flush();
1059                        return MS::kFailure;
1060                }
1061                // create a new animation
1062                Animation a;
1063                a.m_name = clipName;
1064                a.m_length = length;
1065                a.m_tracks.clear();
1066                // if we're using shared geometry, create a single animation track for the whole mesh
1067                if (params.useSharedGeom)
1068                {
1069                        // load the animation track
1070                        stat = loadMeshTrack(a,times,params);
1071                        if (stat != MS::kSuccess)
1072                        {
1073                                std::cout << "Error loading mesh vertex animation\n";
1074                                std::cout.flush();
1075                        }
1076                }
1077                // else creae a different animation track for each submesh
1078                else
1079                {
1080                        // load all tracks (one for each submesh)
1081                        stat = loadSubmeshTracks(a,times,params);
1082                        if (stat != MS::kSuccess)
1083                        {
1084                                std::cout << "Error loading submeshes vertex animation\n";
1085                                std::cout.flush();
1086                                return MS::kFailure;
1087                        }
1088                }
1089                // add newly created animation to animations list
1090                m_vertexClips.push_back(a);
1091                // display info
1092                std::cout << "length: " << a.m_length << "\n";
1093                std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n";
1094                std::cout.flush();
1095                // clip successfully loaded
1096                return MS::kSuccess;
1097        }
1098
1099
1100        //load an animation track for the whole mesh (using shared geometry)
1101        MStatus Mesh::loadMeshTrack(Animation& a,std::vector<float> &times, OgreMayaExporter::ParamList &params)
1102        {
1103                int i;
1104                MStatus stat;
1105                // create a new track
1106                Track t;
1107                t.m_type = TT_MORPH;
1108                t.m_target = T_MESH;
1109                t.m_vertexKeyframes.clear();
1110                // get keyframes at given times
1111                for (i=0; i<times.size(); i++)
1112                {
1113                        //set time to wanted sample time
1114                        MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds));
1115                        //load a keyframe for the mesh at current time
1116                        stat = loadKeyframe(t,times[i]-times[0],params);
1117                        if (stat != MS::kSuccess)
1118                        {
1119                                std::cout << "Error reading animation keyframe at time: " << times[i] << "\n";
1120                                std::cout.flush();
1121                        }
1122                }
1123                // add track to given animation
1124                a.addTrack(t);
1125                // track sucessfully loaded
1126                return MS::kSuccess;
1127        }
1128
1129
1130        //load all submesh animation tracks (one for each submesh)
1131        MStatus Mesh::loadSubmeshTracks(Animation& a,std::vector<float> &times, OgreMayaExporter::ParamList &params)
1132        {
1133                int i,j;
1134                MStatus stat;
1135                // create a new track for each submesh
1136                std::vector<Track> tracks;
1137                for (i=0; i<m_submeshes.size(); i++)
1138                {
1139                        Track t;
1140                        t.m_type = TT_MORPH;
1141                        t.m_target = T_SUBMESH;
1142                        t.m_index = i;
1143                        t.m_vertexKeyframes.clear();
1144                        tracks.push_back(t);
1145                }
1146                // get keyframes at given times
1147                for (i=0; i<times.size(); i++)
1148                {
1149                        //set time to wanted sample time
1150                        MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds));
1151                        //load a keyframe for each submesh at current time
1152                        for (j=0; j<m_submeshes.size(); j++)
1153                        {
1154                                stat = m_submeshes[j]->loadKeyframe(tracks[j],times[i]-times[0],params);
1155                                if (stat != MS::kSuccess)
1156                                {
1157                                        std::cout << "Error reading animation keyframe at time: " << times[i] << " for submesh: " << j << "\n";
1158                                        std::cout.flush();
1159                                }
1160                        }
1161                }
1162                // add tracks to given animation
1163                for (i=0; i< tracks.size(); i++)
1164                        a.addTrack(tracks[i]);
1165                // track sucessfully loaded
1166                return MS::kSuccess;
1167                return MS::kSuccess;
1168        }
1169
1170
1171        // Load a keyframe for the whole mesh
1172        MStatus Mesh::loadKeyframe(Track& t,float time,ParamList& params)
1173        {
1174                int i,j;
1175                // create a new keyframe
1176                vertexKeyframe k;
1177                // set keyframe time
1178                k.time = time;
1179                for (i=0; i<m_sharedGeom.dagMap.size(); i++)
1180                {
1181                        // get the mesh Fn
1182                        dagInfo di = m_sharedGeom.dagMap[i];
1183                        MFnMesh mesh(di.dagPath);
1184                        // get vertex positions
1185                        MFloatPointArray points;
1186                        if (params.exportWorldCoords)
1187                                mesh.getPoints(points,MSpace::kWorld);
1188                        else
1189                                mesh.getPoints(points,MSpace::kObject);
1190                        // calculate vertex offsets
1191                        for (j=0; j<di.numVertices; j++)
1192                        {
1193                                vertexPosition pos;
1194                                vertex v = m_sharedGeom.vertices[di.offset+j];
1195                                pos.x = points[v.index].x * params.lum;
1196                                pos.y = points[v.index].y * params.lum;
1197                                pos.z = points[v.index].z * params.lum;
1198                                if (fabs(pos.x) < PRECISION)
1199                                        pos.x = 0;
1200                                if (fabs(pos.y) < PRECISION)
1201                                        pos.y = 0;
1202                                if (fabs(pos.z) < PRECISION)
1203                                        pos.z = 0;
1204                                k.positions.push_back(pos);
1205                        }
1206                }
1207                // add keyframe to given track
1208                t.addVertexKeyframe(k);
1209                // keyframe successfully loaded
1210                return MS::kSuccess;
1211        }
1212
1213/*********************************** Export mesh data **************************************/
1214        // Write to a OGRE binary mesh
1215        MStatus Mesh::writeOgreBinary(ParamList &params)
1216        {
1217                MStatus stat;
1218                int i;
1219                // If no mesh have been exported, skip mesh creation
1220                if (m_submeshes.size() <= 0)
1221                {
1222                        std::cout << "Warning: No meshes selected for export\n";
1223                        std::cout.flush();
1224                        return MS::kFailure;
1225                }
1226                // Construct mesh
1227                Ogre::MeshPtr pMesh = Ogre::MeshManager::getSingleton().createManual(m_name.asChar(), 
1228                        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
1229                // Write shared geometry data
1230                if (params.useSharedGeom)
1231                {
1232                        createOgreSharedGeometry(pMesh,params);
1233                }
1234                // Write submeshes data
1235                for (i=0; i<m_submeshes.size(); i++)
1236                {
1237                        m_submeshes[i]->createOgreSubmesh(pMesh,params);
1238                }
1239                // Set skeleton link (if present)
1240                if (m_pSkeleton && params.exportSkeleton)
1241                {
1242                        int ri = params.skeletonFilename.rindex('\\');
1243                        int end = params.skeletonFilename.length() - 1;
1244                        MString filename = params.skeletonFilename.substring(ri+1,end);
1245                        pMesh->setSkeletonName(filename.asChar());
1246                }
1247                // Write poses
1248                if (params.exportBlendShapes)
1249                {
1250                        createOgrePoses(pMesh,params);
1251                }
1252                // Write vertex animations
1253                if (params.exportVertAnims)
1254                {
1255                        createOgreVertexAnimations(pMesh,params);
1256                }
1257                // Write pose animations
1258                if (params.exportBSAnims)
1259                {
1260                        createOgrePoseAnimations(pMesh,params);
1261                }
1262                // Create a bounding box for the mesh
1263                Ogre::AxisAlignedBox bbox = pMesh->getBounds();
1264                for(i=0; i<m_submeshes.size(); i++)
1265                {
1266                        MPoint min1 = m_submeshes[i]->m_boundingBox.min();
1267                        MPoint max1 = m_submeshes[i]->m_boundingBox.max();
1268                        Ogre::Vector3 min2(min1.x,min1.y,min1.z);
1269                        Ogre::Vector3 max2(max1.x,max1.y,max1.z);
1270                        Ogre::AxisAlignedBox newbbox;
1271                        newbbox.setExtents(min2,max2);
1272                        bbox.merge(newbbox);
1273                }
1274                // Define mesh bounds
1275                pMesh->_setBounds(bbox,false);
1276                // Build edges list
1277                if (params.buildEdges)
1278                {
1279                        pMesh->buildEdgeList();
1280                }
1281                // Build tangents
1282                if (params.buildTangents)
1283                {
1284                        bool canBuild = true;
1285                        unsigned short srcTex, destTex;
1286                        try {
1287                                pMesh->suggestTangentVectorBuildParams(srcTex, destTex);
1288                        } catch(Ogre::Exception e) {
1289                                canBuild = false;
1290                        }
1291                        if (canBuild)
1292                                pMesh->buildTangentVectors(srcTex, destTex);
1293                }
1294                // Export the binary mesh
1295                Ogre::MeshSerializer serializer;
1296                serializer.exportMesh(pMesh.getPointer(),params.meshFilename.asChar());
1297                pMesh.setNull();
1298                return MS::kSuccess;
1299        }
1300
1301        // Create shared geometry data for an Ogre mesh
1302        MStatus Mesh::createOgreSharedGeometry(Ogre::MeshPtr pMesh,ParamList& params)
1303        {
1304                int i,j;
1305                MStatus stat;
1306                pMesh->sharedVertexData = new Ogre::VertexData();
1307                pMesh->sharedVertexData->vertexCount = m_sharedGeom.vertices.size();
1308                // Define a new vertex declaration
1309                Ogre::VertexDeclaration* pDecl = new Ogre::VertexDeclaration();
1310                pMesh->sharedVertexData->vertexDeclaration = pDecl;
1311                unsigned buf = 0;
1312                size_t offset = 0;
1313                // Add vertex position
1314                pDecl->addElement(buf,offset,Ogre::VET_FLOAT3,Ogre::VES_POSITION);
1315                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
1316                // Add vertex normal
1317                if (params.exportVertNorm)
1318                {
1319                        pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
1320                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
1321                }
1322                // Add vertex colour
1323                if (params.exportVertCol)
1324                {
1325                        pDecl->addElement(buf, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
1326            offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
1327                }
1328                // Add texture coordinates
1329                for (i=0; i<m_sharedGeom.vertices[0].texcoords.size(); i++)
1330                {
1331                        Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, 2);
1332                        pDecl->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, i);
1333                        offset += Ogre::VertexElement::getTypeSize(uvType);
1334                }
1335                // Get optimal vertex declaration
1336                Ogre::VertexDeclaration* pOptimalDecl = pDecl->getAutoOrganisedDeclaration(params.exportVBA,params.exportBlendShapes || params.exportVertAnims);
1337                // Create the vertex buffer using the newly created vertex declaration
1338                stat = createOgreVertexBuffer(pMesh,pDecl,m_sharedGeom.vertices);
1339                // Write vertex bone assignements list
1340                if (params.exportVBA)
1341                {
1342                        // Create a new vertex bone assignements list
1343                        Ogre::Mesh::VertexBoneAssignmentList vbas;
1344                        // Scan list of shared geometry vertices
1345                        for (i=0; i<m_sharedGeom.vertices.size(); i++)
1346                        {
1347                                vertex v = m_sharedGeom.vertices[i];
1348                                // Add all bone assignements for every vertex to the bone assignements list
1349                                for (j=0; j<v.vbas.size(); j++)
1350                                {
1351                                        Ogre::VertexBoneAssignment vba;
1352                                        vba.vertexIndex = i;
1353                                        vba.boneIndex = v.vbas[j].jointIdx;
1354                                        vba.weight = v.vbas[j].weight;
1355                                        if (vba.weight > 0.0f)
1356                                                vbas.insert(Ogre::Mesh::VertexBoneAssignmentList::value_type(i, vba));
1357                                }
1358                        }
1359                        // Rationalise the bone assignements list
1360                        pMesh->_rationaliseBoneAssignments(pMesh->sharedVertexData->vertexCount,vbas);
1361                        // Add bone assignements to the mesh
1362                        for (Ogre::Mesh::VertexBoneAssignmentList::iterator bi = vbas.begin(); bi != vbas.end(); bi++)
1363                        {
1364                                pMesh->addBoneAssignment(bi->second);
1365                        }
1366                        pMesh->_compileBoneAssignments();
1367                        pMesh->_updateCompiledBoneAssignments();
1368                }
1369                // Reorganize vertex buffers
1370                pMesh->sharedVertexData->reorganiseBuffers(pOptimalDecl);
1371               
1372                return MS::kSuccess;
1373        }
1374
1375        // Create an Ogre compatible vertex buffer
1376        MStatus Mesh::createOgreVertexBuffer(Ogre::MeshPtr pMesh,Ogre::VertexDeclaration* pDecl,const std::vector<vertex>& vertices)
1377        {
1378                Ogre::HardwareVertexBufferSharedPtr vbuf = 
1379                        Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pDecl->getVertexSize(0),
1380                        pMesh->sharedVertexData->vertexCount, 
1381                        Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1382                pMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf);
1383                size_t vertexSize = pDecl->getVertexSize(0);
1384                char* pBase = static_cast<char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
1385                Ogre::VertexDeclaration::VertexElementList elems = pDecl->findElementsBySource(0);
1386                Ogre::VertexDeclaration::VertexElementList::iterator ei, eiend;
1387                eiend = elems.end();
1388                float* pFloat;
1389                // Fill the vertex buffer with shared geometry data
1390                long vi;
1391                Ogre::ColourValue col;
1392                float ucoord, vcoord;
1393                for (vi=0; vi<vertices.size(); vi++)
1394                {
1395                        int iTexCoord = 0;
1396                        vertex v = vertices[vi];
1397                        for (ei = elems.begin(); ei != eiend; ++ei)
1398                        {
1399                                Ogre::VertexElement& elem = *ei;
1400                                switch(elem.getSemantic())
1401                                {
1402                                case Ogre::VES_POSITION:
1403                                        elem.baseVertexPointerToElement(pBase, &pFloat);
1404                                        *pFloat++ = v.x;
1405                                        *pFloat++ = v.y;
1406                                        *pFloat++ = v.z;
1407                                        break;
1408                                case Ogre::VES_NORMAL:
1409                                        elem.baseVertexPointerToElement(pBase, &pFloat);
1410                                        *pFloat++ = v.n.x;
1411                                        *pFloat++ = v.n.y;
1412                                        *pFloat++ = v.n.z;
1413                                        break;
1414                                case Ogre::VES_DIFFUSE:
1415                                        elem.baseVertexPointerToElement(pBase, &pFloat);
1416                                        *pFloat++ = v.r;
1417                                        *pFloat++ = v.g;
1418                                        *pFloat++ = v.b;
1419                                        *pFloat++ = v.a;
1420                                        break;
1421                                case Ogre::VES_TEXTURE_COORDINATES:
1422                                        elem.baseVertexPointerToElement(pBase, &pFloat);
1423                                        ucoord = v.texcoords[iTexCoord].u;
1424                                        vcoord = v.texcoords[iTexCoord].v;
1425                                        *pFloat++ = ucoord;
1426                                        *pFloat++ = vcoord;
1427                                        iTexCoord++;
1428                                        break;
1429                                }
1430                        }
1431                        pBase += vertexSize;
1432                }
1433                vbuf->unlock();
1434                return MS::kSuccess;
1435        }
1436        // Create mesh poses for an Ogre mesh
1437        MStatus Mesh::createOgrePoses(Ogre::MeshPtr pMesh,ParamList& params)
1438        {
1439                int i,j,k;
1440                if (params.useSharedGeom)
1441                {
1442                        // Read poses associated from all blendshapes associated to the shared geometry
1443                        for (i=0; i<m_sharedGeom.dagMap.size(); i++)
1444                        {
1445                                BlendShape* pBS = m_sharedGeom.dagMap[i].pBlendShape;
1446                                // Check if we have a blend shape associated to this subset of the shared geometry
1447                                if (pBS)
1448                                {
1449                                        // Get all poses from current blend shape deformer
1450                                        for (j=0; j<pBS->getPoses().size(); j++)
1451                                        {
1452                                                // Get the pose
1453                                                pose* p = &(pBS->getPoses()[j]);
1454                                                if (p->name == "")
1455                                                {
1456                                                        p->name = "pose";
1457                                                        p->name += j;
1458                                                }
1459                                                // Create a new pose for the ogre mesh
1460                                                Ogre::Pose* pPose = pMesh->createPose(0,p->name.asChar());
1461                                                // Set the pose attributes
1462                                                for (k=0; k<p->offsets.size(); k++)
1463                                                {
1464                                                        Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z);
1465                                                        pPose->addVertex(p->offsets[k].index,offset);
1466                                                }
1467                                        }
1468                                }
1469                        }
1470                }
1471                else
1472                {
1473                        // Get poses associated to the submeshes
1474                        for (i=0; i<m_submeshes.size(); i++)
1475                        {
1476                                BlendShape* pBS = m_submeshes[i]->m_pBlendShape;
1477                                // Check if this submesh has a blend shape deformer associated
1478                                if (pBS)
1479                                {
1480                                        // Get all poses from current blend shape deformer
1481                                        for (j=0; j<pBS->getPoses().size(); j++)
1482                                        {
1483                                                // Get the pose
1484                                                pose* p = &(pBS->getPoses()[j]);
1485                                                if (p->name == "")
1486                                                {
1487                                                        p->name = "pose";
1488                                                        p->name += j;
1489                                                }
1490                                                // Create a new pose for the ogre mesh
1491                                                Ogre::Pose* pPose = pMesh->createPose(p->index,p->name.asChar());
1492                                                // Set the pose attributes
1493                                                for (k=0; k<p->offsets.size(); k++)
1494                                                {
1495                                                        Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z);
1496                                                        pPose->addVertex(p->offsets[k].index,offset);
1497                                                }
1498                                        }
1499                                }
1500                        }
1501                }
1502                return MS::kSuccess;
1503        }
1504        // Create vertex animations for an Ogre mesh
1505        MStatus Mesh::createOgreVertexAnimations(Ogre::MeshPtr pMesh,ParamList& params)
1506        {
1507                int i,j,k;
1508                std::cout << "pippo\n";
1509                std::cout.flush();
1510                // Read the list of vertex animation clips
1511                for (i=0; i<m_vertexClips.size(); i++)
1512                {
1513                        // Create a new animation
1514                        Ogre::Animation* pAnimation = pMesh->createAnimation(m_vertexClips[i].m_name.asChar(),m_vertexClips[i].m_length);
1515                        // Create all tracks for current animation
1516                        for (j=0; j<m_vertexClips[i].m_tracks.size(); j++)
1517                        {
1518                                Track* t = &(m_vertexClips[i].m_tracks[j]);
1519                                // Create a new track
1520                                Ogre::VertexAnimationTrack* pTrack;
1521                                if (t->m_target == T_MESH)
1522                                        pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_MORPH);
1523                                else
1524                                {
1525                                        pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData,
1526                                                Ogre::VAT_MORPH);
1527                                }
1528                                // Create keyframes for current track
1529                                for (k=0; k<t->m_vertexKeyframes.size(); k++)
1530                                {
1531                                        // Create a new keyframe
1532                                        Ogre::VertexMorphKeyFrame* pKeyframe = pTrack->createVertexMorphKeyFrame(t->m_vertexKeyframes[k].time);
1533                                        // Create vertex buffer for current keyframe
1534                                        Ogre::HardwareVertexBufferSharedPtr pBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
1535                                                Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
1536                                                t->m_vertexKeyframes[k].positions.size(),
1537                                                Ogre::HardwareBuffer::HBU_STATIC, true);
1538                                        float* pFloat = static_cast<float*>(pBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
1539                                        // Fill the vertex buffer with vertex positions
1540                                        int vi;
1541                                        std::vector<vertexPosition>& positions = t->m_vertexKeyframes[k].positions;
1542                                        for (vi=0; vi<positions.size(); vi++)
1543                                        {
1544                                                *pFloat++ = static_cast<float>(positions[vi].x);
1545                                                *pFloat++ = static_cast<float>(positions[vi].y);
1546                                                *pFloat++ = static_cast<float>(positions[vi].z);
1547                                        }
1548                                        // Unlock vertex buffer
1549                                        pBuffer->unlock();
1550                                        // Set vertex buffer for current keyframe
1551                                        pKeyframe->setVertexBuffer(pBuffer);
1552                                }
1553                        }
1554                }
1555                return MS::kSuccess;
1556        }
1557        // Create pose animations for an Ogre mesh
1558        MStatus Mesh::createOgrePoseAnimations(Ogre::MeshPtr pMesh,ParamList& params)
1559        {
1560                int i,j,k;
1561                // Get all loaded blend shape clips
1562                for (i=0; i<m_BSClips.size(); i++)
1563                {
1564                        // Create a new animation for each clip
1565                        Ogre::Animation* pAnimation = pMesh->createAnimation(m_BSClips[i].m_name.asChar(),m_BSClips[i].m_length);
1566                        // Create animation tracks for this animation
1567                        for (j=0; j<m_BSClips[i].m_tracks.size(); j++)
1568                        {
1569                                Track* t = &m_BSClips[i].m_tracks[j];
1570                                // Create a new track
1571                                Ogre::VertexAnimationTrack* pTrack;
1572                                if (t->m_target == T_MESH)
1573                                        pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_POSE);
1574                                else
1575                                {
1576                                        pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData,
1577                                                Ogre::VAT_POSE);
1578                                }
1579                                // Create keyframes for current track
1580                                for (k=0; k<t->m_vertexKeyframes.size(); k++)
1581                                {
1582                                        Ogre::VertexPoseKeyFrame* pKeyframe = pTrack->createVertexPoseKeyFrame(t->m_vertexKeyframes[k].time);
1583                                        int pri;
1584                                        for (pri=0; pri<t->m_vertexKeyframes[k].poserefs.size(); pri++)
1585                                        {
1586                                                vertexPoseRef* pr = &t->m_vertexKeyframes[k].poserefs[pri];
1587                                                pKeyframe->addPoseReference(pr->poseIndex,pr->poseWeight);
1588                                        }
1589                                }
1590                        }
1591                }
1592                return MS::kSuccess;
1593        }
1594
1595}; //end of namespace
Note: See TracBrowser for help on using the repository browser.