Logo Search packages:      
Sourcecode: ogre version File versions

mesh.cpp

////////////////////////////////////////////////////////////////////////////////
// mesh.cpp
// Author     : Francesco Giordana
// Start Date : January 13, 2005
// Copyright  : (C) 2006 by Francesco Giordana
// Email      : fra.giordana@tiscali.it
////////////////////////////////////////////////////////////////////////////////

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

#include "mesh.h"
#include <maya/MFnMatrixData.h>

namespace OgreMayaExporter
{
      /***** Class Mesh *****/
      // constructor
      Mesh::Mesh(const MString& name)
      {
            m_name = name;
            m_numTriangles = 0;
            m_pSkeleton = NULL;
            m_sharedGeom.vertices.clear();
            m_sharedGeom.dagMap.clear();
            m_vertexClips.clear();
            m_BSClips.clear();
      }

      // destructor
      Mesh::~Mesh()
      {
            clear();
      }

      // clear data
      void Mesh::clear()
      {
            int i;
            m_name = "";
            m_numTriangles = 0;
            for (i=0; i<m_submeshes.size(); i++)
                  delete m_submeshes[i];
            for (i=0; i<m_sharedGeom.dagMap.size(); i++)
            {
                  if (m_sharedGeom.dagMap[i].pBlendShape)
                        delete m_sharedGeom.dagMap[i].pBlendShape;
            }
            m_sharedGeom.vertices.clear();
            m_sharedGeom.dagMap.clear();
            m_vertexClips.clear();
            m_BSClips.clear();
            m_uvsets.clear();
            m_submeshes.clear();
            if (m_pSkeleton)
                  delete m_pSkeleton;
            m_pSkeleton = NULL;
      }

      // get pointer to linked skeleton
      Skeleton* Mesh::getSkeleton()
      {
            return m_pSkeleton;
      }

      /*******************************************************************************
       *                    Load mesh data from a Maya node                          *
       *******************************************************************************/
      MStatus Mesh::load(const MDagPath& meshDag,ParamList &params)
      {
            MStatus stat;
            // Check that given DagPath corresponds to a mesh node
            if (!meshDag.hasFn(MFn::kMesh))
                  return MS::kFailure;

            // Set mesh name
            m_name = "mayaExport";

            // Initialise temporary variables
            newvertices.clear();
            newweights.clear();
            newjointIds.clear();
            newuvsets.clear();
            newpoints.clear();
            newnormals.clear();
            params.currentRootJoints.clear();
            opposite = false;
            shaders.clear();
            shaderPolygonMapping.clear();
            polygonSets.clear();
            pSkinCluster = NULL;
            pBlendShape = NULL;

            // Get mesh uvsets
            stat = getUVSets(meshDag);          
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error retrieving uvsets for current mesh\n";
                  std::cout.flush();
            }
            // Get linked skin cluster
            stat = getSkinCluster(meshDag,params);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error retrieving skin cluster linked to current mesh\n";
                  std::cout.flush();
            }
            // Get linked blend shape deformer
            stat = getBlendShapeDeformer(meshDag,params);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error retrieving blend shape deformer linked to current mesh\n";
                  std::cout.flush();
            }
            // Get connected shaders
            stat = getShaders(meshDag);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error getting shaders connected to current mesh\n";
                  std::cout.flush();
            }
            // Get vertex data
            stat = getVertices(meshDag,params);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error retrieving vertex data for current mesh\n";
                  std::cout.flush();
            }
            // Get vertex bone weights
            if (pSkinCluster)
            {
                  getVertexBoneWeights(meshDag,params);
                  if (stat != MS::kSuccess)
                  {
                        std::cout << "Error retrieving veretex bone assignements for current mesh\n";
                        std::cout.flush();
                  }
            }
            // Get faces data
            stat = getFaces(meshDag,params);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error retrieving faces data for current mesh\n";
                  std::cout.flush();
            }
            // Build shared geometry
            if (params.useSharedGeom)
            {
                  stat = buildSharedGeometry(meshDag,params);
                  if (stat != MS::kSuccess)
                  {
                        std::cout << "Error building shared geometry for current mesh\n";
                        std::cout.flush();
                  }
            }
            // Create submeshes (a different submesh for every different shader linked to the mesh)
            stat = createSubmeshes(meshDag,params);
            if (stat != MS::kSuccess)
            {
                  std::cout << "Error creating submeshes for current mesh\n";
                  std::cout.flush();
            }
            // Free up memory
            newvertices.clear();
            newweights.clear();
            newjointIds.clear();
            newpoints.clear();
            newnormals.clear();
            newuvsets.clear();
            shaders.clear();
            shaderPolygonMapping.clear();
            polygonSets.clear();
            if (pSkinCluster)
                  delete pSkinCluster;
            pBlendShape = NULL;

            return MS::kSuccess;
      }


      /*******************************************************************************
       *                    Load mesh animations from Maya                           *
       *******************************************************************************/
      // Load vertex animations
      MStatus Mesh::loadAnims(ParamList& params)
      {
            MStatus stat;
            int i;
            // save current time for later restore
            MTime curTime = MAnimControl::currentTime();
            std::cout << "Loading vertex animations...\n";
            std::cout.flush();
            // clear animations data
            m_vertexClips.clear();
            // load the requested clips
            for (i=0; i<params.vertClipList.size(); i++)
            {
                  std::cout << "Loading clip " << params.vertClipList[i].name.asChar() << "\n";
                  std::cout.flush();
                  stat = loadClip(params.vertClipList[i].name,params.vertClipList[i].start,
                        params.vertClipList[i].stop,params.vertClipList[i].rate,params);
                  if (stat == MS::kSuccess)
                  {
                        std::cout << "Clip successfully loaded\n";
                        std::cout.flush();
                  }
                  else
                  {
                        std::cout << "Failed loading clip\n";
                        std::cout.flush();
                  }
            }
            //restore current time
            MAnimControl::setCurrentTime(curTime);
            return MS::kSuccess;
      }



      // Load blend shape deformers
      MStatus Mesh::loadBlendShapes(ParamList &params)
      {
            MStatus stat;
            int i;
            std::cout << "Loading blend shape poses...\n";
            std::cout.flush();
            // Set envelopes of all blend shape deformers to 0
            if (params.useSharedGeom)
            {
                  for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
                  {
                        dagInfo di = m_sharedGeom.dagMap[i];
                        if (di.pBlendShape)
                              di.pBlendShape->setEnvelope(0);
                  }
            }
            else
            {
                  for (i=0; i<m_submeshes.size(); i++)
                  {
                        Submesh* pSubmesh = m_submeshes[i];
                        if (pSubmesh->m_pBlendShape)
                              pSubmesh->m_pBlendShape->setEnvelope(0);
                  }
            }
            // Get the blend shape poses
            if (params.useSharedGeom)
            {
                  for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
                  {
                        dagInfo di = m_sharedGeom.dagMap[i];
                        if (di.pBlendShape)
                              di.pBlendShape->loadPoses(di.dagPath,params,m_sharedGeom.vertices,di.numVertices,di.offset);
                  }
            }
            else
            {
                  for (i=0; i<m_submeshes.size(); i++)
                  {
                        Submesh* pSubmesh = m_submeshes[i];
                        if (pSubmesh->m_pBlendShape)
                              pSubmesh->m_pBlendShape->loadPoses(pSubmesh->m_dagPath,params,pSubmesh->m_vertices,
                                    pSubmesh->m_vertices.size(),0,i);
                  }
            }
            // Restore blend shape deformers original envelopes
            if (params.useSharedGeom)
            {
                  for  (i=0; i<m_sharedGeom.dagMap.size(); i++)
                  {
                        dagInfo di = m_sharedGeom.dagMap[i];
                        if (di.pBlendShape)
                              di.pBlendShape->restoreEnvelope();
                  }
            }
            else
            {
                  for (i=0; i<m_submeshes.size(); i++)
                  {
                        Submesh* pSubmesh = m_submeshes[i];
                        if (pSubmesh->m_pBlendShape)
                              pSubmesh->m_pBlendShape->restoreEnvelope();
                  }
            }
            // Read blend shape animations
            if (params.exportBSAnims)
            {
                  stat = loadBlendShapeAnimations(params);
            }
            return MS::kSuccess;
      }

      // Load blend shape animations
      MStatus Mesh::loadBlendShapeAnimations(ParamList& params)
      {
            int i,j,k;
            std::cout << "Loading blend shape animations...\n";
            std::cout.flush();
            // Read the list of blend shape clips to export
            for (i=0; i<params.BSClipList.size(); i++)
            {
                  int startPoseId = 0;
                  clipInfo ci = params.BSClipList[i];
                  // Create a new animation for every clip
                  Animation a;
                  a.m_name = ci.name;
                  a.m_length = ci.stop - ci.start;
                  a.m_tracks.clear();
                  std::cout << "clip " << ci.name.asChar() << "\n";
                  // Read animation tracks from the blend shape deformer
                  if (params.useSharedGeom)
                  {
                        // Create a track for each blend shape
                        std::vector<Track> tracks;
                        for  (j=0; j<m_sharedGeom.dagMap.size(); j++)
                        {
                              dagInfo di = m_sharedGeom.dagMap[j];
                              if (di.pBlendShape)
                              {
                                    Track t = di.pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId);
                                    tracks.push_back(t);
                                    startPoseId += di.pBlendShape->getPoses().size();
                              }
                        }
                        // Merge the tracks into a single track (shared geometry must have a single animation track)
                        if (tracks.size() > 0)
                        {
                              Track newTrack;
                              // Merge keyframes at the same time position from all tracks
                              for (j=0; j<tracks[0].m_vertexKeyframes.size(); j++)
                              {
                                    // Create a new keyframe
                                    vertexKeyframe newKeyframe;
                                    newKeyframe.time = tracks[0].m_vertexKeyframes[j].time;
                                    // Get keyframe at current position from all tracks
                                    for (k=0; k<tracks.size(); k++)
                                    {
                                          vertexKeyframe* pSrcKeyframe = &tracks[k].m_vertexKeyframes[j];
                                          int pri;
                                          // Add pose references from this keyframe to the new keyframe for the joined track
                                          for (pri=0; pri<pSrcKeyframe->poserefs.size(); pri++)
                                          {
                                                // Create a new pose reference
                                                vertexPoseRef poseref;
                                                // Copy pose reference settings from source keyframe
                                                poseref.poseIndex = pSrcKeyframe->poserefs[pri].poseIndex;
                                                poseref.poseWeight = pSrcKeyframe->poserefs[pri].poseWeight;
                                                // Add the new pose reference to the new keyframe
                                                newKeyframe.poserefs.push_back(poseref);
                                          }
                                    }
                                    // Add the keyframe to the new joined track
                                    newTrack.m_vertexKeyframes.push_back(newKeyframe);
                              }
                              // Add the joined track to current animation clip
                              a.addTrack(newTrack);
                        }
                  }
                  else
                  {
                        // Create a track for each submesh
                        std::vector<Track> tracks;
                        for (j=0; j<m_submeshes.size(); j++)
                        {
                              Submesh* pSubmesh = m_submeshes[j];
                              if (pSubmesh->m_pBlendShape)
                              {
                                    Track t = pSubmesh->m_pBlendShape->loadTrack(ci.start,ci.stop,ci.rate,params,startPoseId);
                                    a.addTrack(t);
                                    startPoseId += pSubmesh->m_pBlendShape->getPoses().size();
                              }
                        }
                  }
                  std::cout << "length: " << a.m_length << "\n";
                  std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n";
                  std::cout.flush();
                  m_BSClips.push_back(a);
            }
            return MS::kSuccess;
      }
/******************** Methods to parse geometry data from Maya ************************/
      // Get uvsets info from the maya mesh
      MStatus Mesh::getUVSets(const MDagPath& meshDag)
      {
            MFnMesh mesh(meshDag);
            int i;
            MStatus stat;
            // Get uv texture coordinate sets' names
            if (mesh.numUVSets() > 0)
            {
                  stat = mesh.getUVSetNames(newuvsets);
                  if (MS::kSuccess != stat)
                  {
                        std::cout << "Error retrieving UV sets names\n";
                        std::cout.flush();
                        return MS::kFailure;
                  }
            }
            // Save uvsets info
            for (i=m_uvsets.size(); i<newuvsets.length(); i++)
            {
                  uvset uv;
                  uv.size = 2;
                  m_uvsets.push_back(uv);
            }
            return MS::kSuccess;
      }


      // Get skin cluster linked to the maya mesh
      MStatus Mesh::getSkinCluster(const MDagPath &meshDag, ParamList &params)
      {
            MStatus stat;
            MFnMesh mesh(meshDag);
            pSkinCluster = NULL;
            if (params.exportVBA || params.exportSkeleton)
            {
                  // get connected skin clusters (if present)
                  MItDependencyNodes kDepNodeIt( MFn::kSkinClusterFilter );            
                  for( ;!kDepNodeIt.isDone() && !pSkinCluster; kDepNodeIt.next()) 
                  {            
                        MObject kObject = kDepNodeIt.item();
                        pSkinCluster = new MFnSkinCluster(kObject);
                        unsigned int uiNumGeometries = pSkinCluster->numOutputConnections();
                        unsigned int uiGeometry;
                        for(uiGeometry = 0; uiGeometry < uiNumGeometries; ++uiGeometry ) 
                        {
                              unsigned int uiIndex = pSkinCluster->indexForOutputConnection(uiGeometry);
                              MObject kOutputObject = pSkinCluster->outputShapeAtIndex(uiIndex);
                              if(kOutputObject == mesh.object()) 
                              {
                                    std::cout << "Found skin cluster " << pSkinCluster->name().asChar() << " for mesh " 
                                          << mesh.name().asChar() << "\n"; 
                                    std::cout.flush();
                              }     
                              else
                              {
                                    delete pSkinCluster;
                                    pSkinCluster = NULL;
                              }
                        }
                  }
                  if (pSkinCluster)
                  {
                        // load the skeleton
                        std::cout << "Loading skeleton data...\n";
                        std::cout.flush();
                        if (!m_pSkeleton)
                              m_pSkeleton = new Skeleton();
                        stat = m_pSkeleton->load(pSkinCluster,params);
                        if (MS::kSuccess != stat)
                        {
                              std::cout << "Error loading skeleton data\n";
                              std::cout.flush();
                        }
                        else
                        {
                              std::cout << "OK\n";
                              std::cout.flush();
                        }
                  }
            }
            return MS::kSuccess;
      }


      // Get blend shape deformer linked to the maya mesh
      MStatus Mesh::getBlendShapeDeformer(const MDagPath &meshDag, OgreMayaExporter::ParamList &params)
      {
            MStatus stat;
            MFnMesh mesh(meshDag);
            if (params.exportBlendShapes)
            {
                  // get connected blend shape deformer (if present)
                  MItDependencyNodes kDepNodeIt( MFn::kBlendShape );            
                  for( ;!kDepNodeIt.isDone() && !pBlendShape; kDepNodeIt.next()) 
                  {   
                        MObject kObject = kDepNodeIt.item();
                        MItDependencyGraph itGraph(kObject,MFn::kMesh,MItDependencyGraph::kDownstream,MItDependencyGraph::kDepthFirst);
                        for (;!itGraph.isDone() && !pBlendShape; itGraph.next())
                        {
                              MFnMesh connectedMesh(itGraph.thisNode());
                              if (connectedMesh.fullPathName() == mesh.fullPathName())
                              {
                                    pBlendShape = new BlendShape();
                                    pBlendShape->load(kObject);
                                    std::cout << "Found blend shape deformer " << pBlendShape->getName().asChar() << " for mesh " 
                                          << mesh.name().asChar() << "\n"; 
                              }     
                        }
                  }
            }
            return MS::kSuccess;
      }
      // Get connected shaders
      MStatus Mesh::getShaders(const MDagPath& meshDag)
      {
            MStatus stat;
            MFnMesh mesh(meshDag);
            stat = mesh.getConnectedShaders(0,shaders,shaderPolygonMapping);
            std::cout.flush();
            if (MS::kSuccess != stat)
            {
                  std::cout << "Error getting connected shaders\n";
                  std::cout.flush();
                  return MS::kFailure;
            }
            std::cout << "Found " << shaders.length() << " connected shaders\n";
            std::cout.flush();
            if (shaders.length() <= 0)
            {
                  std::cout << "No connected shaders, skipping mesh\n";
                  std::cout.flush();
                  return MS::kFailure;
            }
            // create a series of arrays of faces for each different submesh
            polygonSets.clear();
            polygonSets.resize(shaders.length());
            return MS::kSuccess;
      }


      // Get vertex data
      MStatus Mesh::getVertices(const MDagPath &meshDag, OgreMayaExporter::ParamList &params)
      {
            int i;
            MFnMesh mesh(meshDag);
            // prepare vertex table
            newvertices.resize(mesh.numVertices());
            newweights.resize(mesh.numVertices());
            newjointIds.resize(mesh.numVertices());
            for (i=0; i<newvertices.size(); i++)
            {
                  newvertices[i].pointIdx = -1;
                  newvertices[i].normalIdx = -1;
                  newvertices[i].next = -2;
            }
            //get vertex positions from mesh
            if (params.exportWorldCoords || (pSkinCluster && params.exportSkeleton))
                  mesh.getPoints(newpoints,MSpace::kWorld);
            else
                  mesh.getPoints(newpoints,MSpace::kTransform);
            //get list of normals from mesh data
            if (params.exportWorldCoords)
                  mesh.getNormals(newnormals,MSpace::kWorld);
            else
                  mesh.getNormals(newnormals,MSpace::kTransform);
            //check the "opposite" attribute to see if we have to flip normals
            mesh.findPlug("opposite",true).getValue(opposite);
            return MS::kSuccess;
      }


      // Get vertex bone assignements
      MStatus Mesh::getVertexBoneWeights(const MDagPath& meshDag, OgreMayaExporter::ParamList &params)
      {
            int i,j,k;
            unsigned int numWeights;
            MStatus stat;
            std::cout << "Get vbas\n";
            std::cout.flush();
            MItGeometry iterGeom(meshDag);
            for (i=0; !iterGeom.isDone(); iterGeom.next(), i++)
            {
                  MObject component = iterGeom.component();
                  MFloatArray vertexWeights;
                  stat=pSkinCluster->getWeights(meshDag,component,vertexWeights,numWeights);
      /*          //normalize vertex weights
                  int widx;
                  // first, truncate the weights to given precision
                  long weightSum = 0;
                  for (widx=0; widx < vertexWeights.length(); widx++)
                  {
                        long w = (long) (((float)vertexWeights[widx]) / ((float)PRECISION));
                        vertexWeights[widx] = w;
                        weightSum += w;
                  }
                  // then divide by the sum of the weights to add up to 1 
                  // (if there is at least one weight > 0)
                  if (weightSum > 0)
                  {
                        float newSum = 0;
                        for (widx=0; widx < numWeights; widx++)
                        {
                              long w = (long) ((float)vertexWeights[widx] / ((float)PRECISION));
                              w = (long) (((float)w) / ((float)weightSum));
                              vertexWeights[widx] = (float) (((long)w) * ((float)PRECISION));
                              newSum += vertexWeights[widx];
                        }
                        if (newSum < 1.0f)
                              vertexWeights[numWeights-1] += PRECISION;
                  }
                  // else set all weights to 0
                  else
                  {
                        for (widx=0; widx < numWeights; widx++)
                              vertexWeights[widx] = 0;
                  }*/
                  // save the normalized weights
                  newweights[i]=vertexWeights;
                  if (MS::kSuccess != stat)
                  {
                        std::cout << "Error retrieving vertex weights\n";
                        std::cout.flush();
                  }
                  // get ids for the joints
                  if (m_pSkeleton)
                  {
                        MDagPathArray influenceObjs;
                        pSkinCluster->influenceObjects(influenceObjs,&stat);
                        if (MS::kSuccess != stat)
                        {
                              std::cout << "Error retrieving influence objects for given skin cluster\n";
                              std::cout.flush();
                        }
                        newjointIds[i].setLength(newweights[i].length());
                        for (j=0; j<influenceObjs.length(); j++)
                        {
                              bool foundJoint = false;
                              MString partialPathName = influenceObjs[j].partialPathName(); 
                              for (k=0; k<m_pSkeleton->getJoints().size() && !foundJoint; k++)
                              {
                                    if (partialPathName == m_pSkeleton->getJoints()[k].name)
                                    {
                                          foundJoint=true;
                                          newjointIds[i][j] = m_pSkeleton->getJoints()[k].id;
                                    }
                              }
                        }
                  }
            }
            return MS::kSuccess;
      }


      // Get faces data
      MStatus Mesh::getFaces(const MDagPath &meshDag, ParamList &params)
      {
            int i,j,k;
            MStatus stat;
            MFnMesh mesh(meshDag);
            // create an iterator to go through mesh polygons
            if (mesh.numPolygons() > 0)
            {
                  std::cout << "Iterate over mesh polygons\n";
                  std::cout.flush();
                  MItMeshPolygon faceIter(mesh.object(),&stat);
                  if (MS::kSuccess != stat)
                  {
                        std::cout << "Error accessing mesh polygons\n";
                        std::cout.flush();
                        return MS::kFailure;
                  }
                  std::cout << "num polygons = " << mesh.numPolygons() << "\n";
                  std::cout.flush();
                  // iterate over mesh polygons
                  for (; !faceIter.isDone(); faceIter.next())
                  {
                        int numTris=0;
                        int iTris;
                        bool different;
                        int vtxIdx, nrmIdx;
                        faceIter.numTriangles(numTris);
                        // for every triangle composing current polygon extract triangle info
                        for (iTris=0; iTris<numTris; iTris++)
                        {
                              MPointArray triPoints;
                              MIntArray tempTriVertexIdx,triVertexIdx;
                              int idx;
                              // create a new face to store triangle info
                              face newFace;
                              // extract triangle vertex indices
                              faceIter.getTriangle(iTris,triPoints,tempTriVertexIdx);
                              // convert indices to face-relative indices
                              MIntArray polyIndices;
                              faceIter.getVertices(polyIndices);
                              unsigned int iPoly, iObj;
                              for (iObj=0; iObj < tempTriVertexIdx.length(); ++iObj)
                              {
                                    // iPoly is face-relative vertex index
                                    for (iPoly=0; iPoly < polyIndices.length(); ++iPoly)
                                    {
                                          if (tempTriVertexIdx[iObj] == polyIndices[iPoly]) 
                                          {
                                                triVertexIdx.append(iPoly);
                                                break;
                                          }
                                    }
                              }
                              // iterate over triangle's vertices
                              for (i=0; i<3; i++)
                              {
                                    different = true;
                                    vtxIdx = faceIter.vertexIndex(triVertexIdx[i],&stat);
                                    if (stat != MS::kSuccess)
                                    {
                                          std::cout << "Could not access vertex position\n";
                                          std::cout.flush();
                                    }
                                    nrmIdx = faceIter.normalIndex(triVertexIdx[i],&stat);
                                    if (stat != MS::kSuccess)
                                    {
                                          std::cout << "Could not access vertex normal\n";
                                          std::cout.flush();
                                    }

                                    // get vertex color
                                    MColor color;
                                    if (faceIter.hasColor(triVertexIdx[i]))
                                    {
                                          stat = faceIter.getColor(color,triVertexIdx[i]);
                                          if (MS::kSuccess != stat)
                                          {
                                                color = MColor(1,1,1,1);
                                          }
                                          if (color.r > 1)
                                                color.r = 1;
                                          else if (color.r < PRECISION)
                                                color.r = 0;
                                          if (color.g > 1)
                                                color.g = 1;
                                          else if (color.g < PRECISION)
                                                color.g = 0;
                                          if (color.b > 1)
                                                color.b = 1;
                                          else if (color.b < PRECISION)
                                                color.b = 0;
                                          if (color.a > 1)
                                                color.a = 1;
                                          else if (color.a < PRECISION)
                                                color.a = 0;
                                    }
                                    else
                                    {
                                          color = MColor(1,1,1,1);
                                    }
                                    if (newvertices[vtxIdx].next == -2) // first time we encounter a vertex in this position
                                    {
                                          // save vertex position
                                          newpoints[vtxIdx].cartesianize();
                                          newvertices[vtxIdx].pointIdx = vtxIdx;
                                          // save vertex normal
                                          newvertices[vtxIdx].normalIdx = nrmIdx;
                                          // save vertex colour
                                          newvertices[vtxIdx].r = color.r;
                                          newvertices[vtxIdx].g = color.g;
                                          newvertices[vtxIdx].b = color.b;
                                          newvertices[vtxIdx].a = color.a;
                                          // save vertex texture coordinates
                                          newvertices[vtxIdx].u.resize(newuvsets.length());
                                          newvertices[vtxIdx].v.resize(newuvsets.length());
                                          // save vbas
                                          newvertices[vtxIdx].vba.resize(newweights[vtxIdx].length());
                                          for (j=0; j<newweights[vtxIdx].length(); j++)
                                          {
                                                newvertices[vtxIdx].vba[j] = (newweights[vtxIdx])[j];
                                          }
                                          // save joint ids
                                          newvertices[vtxIdx].jointIds.resize(newjointIds[vtxIdx].length());
                                          for (j=0; j<newjointIds[vtxIdx].length(); j++)
                                          {
                                                newvertices[vtxIdx].jointIds[j] = (newjointIds[vtxIdx])[j];
                                          }
                                          // save uv sets data
                                          for (j=0; j<newuvsets.length(); j++)
                                          {
                                                float2 uv;
                                                stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
                                                if (MS::kSuccess != stat)
                                                {
                                                      uv[0] = 0;
                                                      uv[1] = 0;
                                                }
                                                newvertices[vtxIdx].u[j] = uv[0];
                                                newvertices[vtxIdx].v[j] = (-1)*(uv[1]-1);
                                          }
                                          // save vertex index in face info
                                          newFace.v[i] = m_sharedGeom.vertices.size() + vtxIdx;
                                          // update value of index to next vertex info (-1 means nothing next)
                                          newvertices[vtxIdx].next = -1;
                                    }
                                    else  // already found at least 1 vertex in this position
                                    {
                                          // check if a vertex with same attributes has been saved already
                                          for (k=vtxIdx; k!=-1 && different; k=newvertices[k].next)
                                          {
                                                different = false;

                                                if (params.exportVertNorm)
                                                {
                                                      MFloatVector n1 = newnormals[newvertices[k].normalIdx];
                                                      MFloatVector n2 = newnormals[nrmIdx];
                                                      if (n1.x!=n2.x || n1.y!=n2.y || n1.z!=n2.z)
                                                      {
                                                            different = true;
                                                      }
                                                }

                                                if ((params.exportVertCol) &&
                                                      (newvertices[k].r!=color.r || newvertices[k].g!=color.g || newvertices[k].b!= color.b || newvertices[k].a!=color.a))
                                                {
                                                      different = true;
                                                }

                                                if (params.exportTexCoord)
                                                {
                                                      for (j=0; j<newuvsets.length(); j++)
                                                      {
                                                            float2 uv;
                                                            stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
                                                            if (MS::kSuccess != stat)
                                                            {
                                                                  uv[0] = 0;
                                                                  uv[1] = 0;
                                                            }
                                                            uv[1] = (-1)*(uv[1]-1);
                                                            if (newvertices[k].u[j]!=uv[0] || newvertices[k].v[j]!=uv[1])
                                                            {
                                                                  different = true;
                                                            }
                                                      }
                                                }

                                                idx = k;
                                          }
                                          // if no identical vertex has been saved, then save the vertex info
                                          if (different)
                                          {
                                                vertexInfo vtx;
                                                // save vertex position
                                                vtx.pointIdx = vtxIdx;
                                                // save vertex normal
                                                vtx.normalIdx = nrmIdx;
                                                // save vertex colour
                                                vtx.r = color.r;
                                                vtx.g = color.g;
                                                vtx.b = color.b;
                                                vtx.a = color.a;
                                                // save vertex vba
                                                vtx.vba.resize(newweights[vtxIdx].length());
                                                for (j=0; j<newweights[vtxIdx].length(); j++)
                                                {
                                                      vtx.vba[j] = (newweights[vtxIdx])[j];
                                                }
                                                // save joint ids
                                                vtx.jointIds.resize(newjointIds[vtxIdx].length());
                                                for (j=0; j<newjointIds[vtxIdx].length(); j++)
                                                {
                                                      vtx.jointIds[j] = (newjointIds[vtxIdx])[j];
                                                }
                                                // save vertex texture coordinates
                                                vtx.u.resize(newuvsets.length());
                                                vtx.v.resize(newuvsets.length());
                                                for (j=0; j<newuvsets.length(); j++)
                                                {
                                                      float2 uv;
                                                      stat = faceIter.getUV(triVertexIdx[i],uv,&newuvsets[j]);
                                                      if (MS::kSuccess != stat)
                                                      {
                                                            uv[0] = 0;
                                                            uv[1] = 0;
                                                      }
                                                      if (fabs(uv[0]) < PRECISION)
                                                            uv[0] = 0;
                                                      if (fabs(uv[1]) < PRECISION)
                                                            uv[1] = 0;
                                                      vtx.u[j] = uv[0];
                                                      vtx.v[j] = (-1)*(uv[1]-1);
                                                }
                                                vtx.next = -1;
                                                newvertices.push_back(vtx);
                                                // save vertex index in face info
                                                newFace.v[i] = m_sharedGeom.vertices.size() + newvertices.size()-1;
                                                newvertices[idx].next = newvertices.size()-1;
                                          }
                                          else
                                          {
                                                newFace.v[i] = m_sharedGeom.vertices.size() + idx;
                                          }
                                    }
                              } // end iteration of triangle vertices
                              // add face info to the array corresponding to the submesh it belongs
                              // skip faces with no shaders assigned
                              if (shaderPolygonMapping[faceIter.index()] >= 0)
                                    polygonSets[shaderPolygonMapping[faceIter.index()]].push_back(newFace);
                        } // end iteration of triangles
                  }
            }
            std::cout << "done reading mesh triangles\n";
            std::cout.flush();
            return MS::kSuccess;
      }


      // Build shared geometry
      MStatus Mesh::buildSharedGeometry(const MDagPath &meshDag,ParamList& params)
      {
            int i,j,k;
            std::cout << "Create list of shared vertices\n";
            std::cout.flush();
            // save a new entry in the shared geometry map: we associate the index of the first 
            // vertex we're loading with the dag path from which it has been read
            dagInfo di;
            di.offset = m_sharedGeom.vertices.size();
            di.dagPath = meshDag;
            di.pBlendShape = pBlendShape;
            // load shared vertices
            for (i=0; i<newvertices.size(); i++)
            {
                  vertex v;
                  vertexInfo vInfo = newvertices[i];
                  // save vertex coordinates (rescale to desired length unit)
                  MPoint point = newpoints[vInfo.pointIdx] * params.lum;
                  if (fabs(point.x) < PRECISION)
                        point.x = 0;
                  if (fabs(point.y) < PRECISION)
                        point.y = 0;
                  if (fabs(point.z) < PRECISION)
                        point.z = 0;
                  v.x = point.x;
                  v.y = point.y;
                  v.z = point.z;
                  // save vertex normal
                  MFloatVector normal = newnormals[vInfo.normalIdx];
                  if (fabs(normal.x) < PRECISION)
                        normal.x = 0;
                  if (fabs(normal.y) < PRECISION)
                        normal.y = 0;
                  if (fabs(normal.z) < PRECISION)
                        normal.z = 0;
                  if (opposite)
                  {
                        v.n.x = -normal.x;
                        v.n.y = -normal.y;
                        v.n.z = -normal.z;
                  }
                  else
                  {
                        v.n.x = normal.x;
                        v.n.y = normal.y;
                        v.n.z = normal.z;
                  }
                  v.n.normalize();
                  // save vertex color
                  v.r = vInfo.r;
                  v.g = vInfo.g;
                  v.b = vInfo.b;
                  v.a = vInfo.a;
                  // save vertex bone assignements
                  for (k=0; k<vInfo.vba.size(); k++)
                  {
                        vba newVba;
                        newVba.jointIdx = vInfo.jointIds[k];
                        newVba.weight = vInfo.vba[k];
                        v.vbas.push_back(newVba);
                  }
                  // save texture coordinates
                  for (k=0; k<vInfo.u.size(); k++)
                  {
                        texcoords newTexCoords;
                        newTexCoords.u = vInfo.u[k];
                        newTexCoords.v = vInfo.v[k];
                        newTexCoords.w = 0;
                        v.texcoords.push_back(newTexCoords);
                  }
                  // save vertex index in maya mesh, to retrieve future positions of the same vertex
                  v.index = vInfo.pointIdx;
                  // add newly created vertex to vertices list
                  m_sharedGeom.vertices.push_back(v);
            }
            // Make sure all vertices have the same number of texture coordinates
            for (i=0; i<m_sharedGeom.vertices.size(); i++)
            {
                  vertex* pV = &m_sharedGeom.vertices[i];
                  for (j=pV->texcoords.size(); j<m_uvsets.size(); j++)
                  {
                        texcoords newTexCoords;
                        newTexCoords.u = 0;
                        newTexCoords.v = 0;
                        newTexCoords.w = 0;
                        pV->texcoords.push_back(newTexCoords);
                  }
            }
            // save number of vertices referring to this mesh dag in the dag path map
            di.numVertices = m_sharedGeom.vertices.size() - di.offset;
            m_sharedGeom.dagMap.push_back(di);
            std::cout << "done creating vertices list\n";
            std::cout.flush();
            return MS::kSuccess;
      }


      // Create submeshes
      MStatus Mesh::createSubmeshes(const MDagPath& meshDag,ParamList& params)
      {
            int i;
            MStatus stat;
            MFnMesh mesh(meshDag);
            for (i=0; i<shaders.length(); i++)
            {
                  // check if the submesh has at least 1 triangle
                  if (polygonSets[i].size() > 0)
                  {
                        //create new submesh
                        Submesh* pSubmesh = new Submesh();
                        //load linked shader
                        stat = pSubmesh->loadMaterial(shaders[i],newuvsets,params);
                        if (stat != MS::kSuccess)
                        {
                              MFnDependencyNode shadingGroup(shaders[i]);
                              std::cout << "Error loading submesh linked to shader " << shadingGroup.name().asChar() << "\n";
                              std::cout.flush();
                              return MS::kFailure;
                        }
                        //load vertex and face data
                        stat = pSubmesh->load(meshDag,polygonSets[i],newvertices,newpoints,newnormals,newuvsets,params,opposite);
                        //if we're not using shared geometry, save a pointer to the blend shape deformer
                        if (pBlendShape && !params.useSharedGeom)
                              pSubmesh->m_pBlendShape = pBlendShape;
                        //add submesh to current mesh
                        m_submeshes.push_back(pSubmesh);
                        //update number of triangles composing the mesh
                        m_numTriangles += pSubmesh->numTriangles();
                  }
            }
            return MS::kSuccess;
      }





/******************** Methods to read vertex animations from Maya ************************/
      //load a vertex animation clip
      MStatus Mesh::loadClip(MString& clipName,float start,float stop,float rate,ParamList& params)
      {
            MStatus stat;
            MString msg;
            std::vector<float> times;
            // calculate times from clip sample rate
            times.clear();
            for (float t=start; t<stop; t+=rate)
                  times.push_back(t);
            times.push_back(stop);
            // get animation length
            float length=0;
            if (times.size() >= 0)
                  length = times[times.size()-1] - times[0];
            if (length < 0)
            {
                  std::cout << "invalid time range for the clip, we skip it\n";
                  std::cout.flush();
                  return MS::kFailure;
            }
            // create a new animation
            Animation a;
            a.m_name = clipName;
            a.m_length = length;
            a.m_tracks.clear();
            // if we're using shared geometry, create a single animation track for the whole mesh
            if (params.useSharedGeom)
            {
                  // load the animation track
                  stat = loadMeshTrack(a,times,params);
                  if (stat != MS::kSuccess)
                  {
                        std::cout << "Error loading mesh vertex animation\n";
                        std::cout.flush();
                  }
            }
            // else creae a different animation track for each submesh
            else
            {
                  // load all tracks (one for each submesh)
                  stat = loadSubmeshTracks(a,times,params);
                  if (stat != MS::kSuccess)
                  {
                        std::cout << "Error loading submeshes vertex animation\n";
                        std::cout.flush();
                        return MS::kFailure;
                  }
            }
            // add newly created animation to animations list
            m_vertexClips.push_back(a);
            // display info
            std::cout << "length: " << a.m_length << "\n";
            std::cout << "num keyframes: " << a.m_tracks[0].m_vertexKeyframes.size() << "\n";
            std::cout.flush();
            // clip successfully loaded
            return MS::kSuccess;
      }


      //load an animation track for the whole mesh (using shared geometry)
      MStatus Mesh::loadMeshTrack(Animation& a,std::vector<float> &times, OgreMayaExporter::ParamList &params)
      {
            int i;
            MStatus stat;
            // create a new track
            Track t;
            t.m_type = TT_MORPH;
            t.m_target = T_MESH;
            t.m_vertexKeyframes.clear();
            // get keyframes at given times
            for (i=0; i<times.size(); i++)
            {
                  //set time to wanted sample time
                  MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds));
                  //load a keyframe for the mesh at current time
                  stat = loadKeyframe(t,times[i]-times[0],params);
                  if (stat != MS::kSuccess)
                  {
                        std::cout << "Error reading animation keyframe at time: " << times[i] << "\n";
                        std::cout.flush();
                  }
            }
            // add track to given animation
            a.addTrack(t);
            // track sucessfully loaded
            return MS::kSuccess;
      }


      //load all submesh animation tracks (one for each submesh)
      MStatus Mesh::loadSubmeshTracks(Animation& a,std::vector<float> &times, OgreMayaExporter::ParamList &params)
      {
            int i,j;
            MStatus stat;
            // create a new track for each submesh
            std::vector<Track> tracks;
            for (i=0; i<m_submeshes.size(); i++)
            {
                  Track t;
                  t.m_type = TT_MORPH;
                  t.m_target = T_SUBMESH;
                  t.m_index = i;
                  t.m_vertexKeyframes.clear();
                  tracks.push_back(t);
            }
            // get keyframes at given times
            for (i=0; i<times.size(); i++)
            {
                  //set time to wanted sample time
                  MAnimControl::setCurrentTime(MTime(times[i],MTime::kSeconds));
                  //load a keyframe for each submesh at current time
                  for (j=0; j<m_submeshes.size(); j++)
                  {
                        stat = m_submeshes[j]->loadKeyframe(tracks[j],times[i]-times[0],params);
                        if (stat != MS::kSuccess)
                        {
                              std::cout << "Error reading animation keyframe at time: " << times[i] << " for submesh: " << j << "\n";
                              std::cout.flush();
                        }
                  }
            }
            // add tracks to given animation
            for (i=0; i< tracks.size(); i++)
                  a.addTrack(tracks[i]);
            // track sucessfully loaded
            return MS::kSuccess;
            return MS::kSuccess;
      }


      // Load a keyframe for the whole mesh
      MStatus Mesh::loadKeyframe(Track& t,float time,ParamList& params)
      {
            int i,j;
            // create a new keyframe
            vertexKeyframe k;
            // set keyframe time
            k.time = time;
            for (i=0; i<m_sharedGeom.dagMap.size(); i++)
            {
                  // get the mesh Fn
                  dagInfo di = m_sharedGeom.dagMap[i];
                  MFnMesh mesh(di.dagPath);
                  // get vertex positions
                  MFloatPointArray points;
                  if (params.exportWorldCoords)
                        mesh.getPoints(points,MSpace::kWorld);
                  else
                        mesh.getPoints(points,MSpace::kObject);
                  // calculate vertex offsets
                  for (j=0; j<di.numVertices; j++)
                  {
                        vertexPosition pos;
                        vertex v = m_sharedGeom.vertices[di.offset+j];
                        pos.x = points[v.index].x * params.lum;
                        pos.y = points[v.index].y * params.lum;
                        pos.z = points[v.index].z * params.lum;
                        if (fabs(pos.x) < PRECISION)
                              pos.x = 0;
                        if (fabs(pos.y) < PRECISION)
                              pos.y = 0;
                        if (fabs(pos.z) < PRECISION)
                              pos.z = 0;
                        k.positions.push_back(pos);
                  }
            }
            // add keyframe to given track
            t.addVertexKeyframe(k);
            // keyframe successfully loaded
            return MS::kSuccess;
      }

/*********************************** Export mesh data **************************************/
      // Write to a OGRE binary mesh
      MStatus Mesh::writeOgreBinary(ParamList &params)
      {
            MStatus stat;
            int i;
            // If no mesh have been exported, skip mesh creation
            if (m_submeshes.size() <= 0)
            {
                  std::cout << "Warning: No meshes selected for export\n";
                  std::cout.flush();
                  return MS::kFailure;
            }
            // Construct mesh
            Ogre::MeshPtr pMesh = Ogre::MeshManager::getSingleton().createManual(m_name.asChar(), 
                  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
            // Write shared geometry data
            if (params.useSharedGeom)
            {
                  createOgreSharedGeometry(pMesh,params);
            }
            // Write submeshes data
            for (i=0; i<m_submeshes.size(); i++)
            {
                  m_submeshes[i]->createOgreSubmesh(pMesh,params);
            }
            // Set skeleton link (if present)
            if (m_pSkeleton && params.exportSkeleton)
            {
                  int ri = params.skeletonFilename.rindex('\\');
                  int end = params.skeletonFilename.length() - 1;
                  MString filename = params.skeletonFilename.substring(ri+1,end);
                  pMesh->setSkeletonName(filename.asChar());
            }
            // Write poses
            if (params.exportBlendShapes)
            {
                  createOgrePoses(pMesh,params);
            }
            // Write vertex animations
            if (params.exportVertAnims)
            {
                  createOgreVertexAnimations(pMesh,params);
            }
            // Write pose animations
            if (params.exportBSAnims)
            {
                  createOgrePoseAnimations(pMesh,params);
            }
            // Create a bounding box for the mesh
            Ogre::AxisAlignedBox bbox = pMesh->getBounds();
            for(i=0; i<m_submeshes.size(); i++)
            {
                  MPoint min1 = m_submeshes[i]->m_boundingBox.min();
                  MPoint max1 = m_submeshes[i]->m_boundingBox.max();
                  Ogre::Vector3 min2(min1.x,min1.y,min1.z);
                  Ogre::Vector3 max2(max1.x,max1.y,max1.z);
                  Ogre::AxisAlignedBox newbbox;
                  newbbox.setExtents(min2,max2);
                  bbox.merge(newbbox);
            }
            // Define mesh bounds
            pMesh->_setBounds(bbox,false);
            // Build edges list
            if (params.buildEdges)
            {
                  pMesh->buildEdgeList();
            }
            // Build tangents
            if (params.buildTangents)
            {
                  bool canBuild = true;
                  unsigned short srcTex, destTex;
                  try {
                        pMesh->suggestTangentVectorBuildParams(srcTex, destTex);
                  } catch(Ogre::Exception e) {
                        canBuild = false;
                  }
                  if (canBuild)
                        pMesh->buildTangentVectors(srcTex, destTex);
            }
            // Export the binary mesh
            Ogre::MeshSerializer serializer;
            serializer.exportMesh(pMesh.getPointer(),params.meshFilename.asChar());
            pMesh.setNull();
            return MS::kSuccess;
      }

      // Create shared geometry data for an Ogre mesh
      MStatus Mesh::createOgreSharedGeometry(Ogre::MeshPtr pMesh,ParamList& params)
      {
            int i,j;
            MStatus stat;
            pMesh->sharedVertexData = new Ogre::VertexData();
            pMesh->sharedVertexData->vertexCount = m_sharedGeom.vertices.size();
            // Define a new vertex declaration
            Ogre::VertexDeclaration* pDecl = new Ogre::VertexDeclaration();
            pMesh->sharedVertexData->vertexDeclaration = pDecl;
            unsigned buf = 0;
            size_t offset = 0;
            // Add vertex position
            pDecl->addElement(buf,offset,Ogre::VET_FLOAT3,Ogre::VES_POSITION);
            offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
            // Add vertex normal
            if (params.exportVertNorm)
            {
                  pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
                  offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
            }
            // Add vertex colour
            if (params.exportVertCol)
            {
                  pDecl->addElement(buf, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
            offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
            }
            // Add texture coordinates
            for (i=0; i<m_sharedGeom.vertices[0].texcoords.size(); i++)
            {
                  Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, 2);
                  pDecl->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, i);
                  offset += Ogre::VertexElement::getTypeSize(uvType);
            }
            // Get optimal vertex declaration
            Ogre::VertexDeclaration* pOptimalDecl = pDecl->getAutoOrganisedDeclaration(params.exportVBA,params.exportBlendShapes || params.exportVertAnims);
            // Create the vertex buffer using the newly created vertex declaration
            stat = createOgreVertexBuffer(pMesh,pDecl,m_sharedGeom.vertices);
            // Write vertex bone assignements list
            if (params.exportVBA)
            {
                  // Create a new vertex bone assignements list
                  Ogre::Mesh::VertexBoneAssignmentList vbas;
                  // Scan list of shared geometry vertices
                  for (i=0; i<m_sharedGeom.vertices.size(); i++)
                  {
                        vertex v = m_sharedGeom.vertices[i];
                        // Add all bone assignements for every vertex to the bone assignements list
                        for (j=0; j<v.vbas.size(); j++)
                        {
                              Ogre::VertexBoneAssignment vba;
                              vba.vertexIndex = i;
                              vba.boneIndex = v.vbas[j].jointIdx;
                              vba.weight = v.vbas[j].weight;
                              if (vba.weight > 0.0f)
                                    vbas.insert(Ogre::Mesh::VertexBoneAssignmentList::value_type(i, vba));
                        }
                  }
                  // Rationalise the bone assignements list
                  pMesh->_rationaliseBoneAssignments(pMesh->sharedVertexData->vertexCount,vbas);
                  // Add bone assignements to the mesh
                  for (Ogre::Mesh::VertexBoneAssignmentList::iterator bi = vbas.begin(); bi != vbas.end(); bi++)
                  {
                        pMesh->addBoneAssignment(bi->second);
                  }
                  pMesh->_compileBoneAssignments();
                  pMesh->_updateCompiledBoneAssignments();
            }
            // Reorganize vertex buffers
            pMesh->sharedVertexData->reorganiseBuffers(pOptimalDecl);
            
            return MS::kSuccess;
      }

      // Create an Ogre compatible vertex buffer
      MStatus Mesh::createOgreVertexBuffer(Ogre::MeshPtr pMesh,Ogre::VertexDeclaration* pDecl,const std::vector<vertex>& vertices)
      {
            Ogre::HardwareVertexBufferSharedPtr vbuf = 
                  Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pDecl->getVertexSize(0),
                  pMesh->sharedVertexData->vertexCount, 
                  Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
            pMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf);
            size_t vertexSize = pDecl->getVertexSize(0);
            char* pBase = static_cast<char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
            Ogre::VertexDeclaration::VertexElementList elems = pDecl->findElementsBySource(0);
            Ogre::VertexDeclaration::VertexElementList::iterator ei, eiend;
            eiend = elems.end();
            float* pFloat;
            // Fill the vertex buffer with shared geometry data
            long vi;
            Ogre::ColourValue col;
            float ucoord, vcoord;
            for (vi=0; vi<vertices.size(); vi++)
            {
                  int iTexCoord = 0;
                  vertex v = vertices[vi];
                  for (ei = elems.begin(); ei != eiend; ++ei)
                  {
                        Ogre::VertexElement& elem = *ei;
                        switch(elem.getSemantic())
                        {
                        case Ogre::VES_POSITION:
                              elem.baseVertexPointerToElement(pBase, &pFloat);
                              *pFloat++ = v.x;
                              *pFloat++ = v.y;
                              *pFloat++ = v.z;
                              break;
                        case Ogre::VES_NORMAL:
                              elem.baseVertexPointerToElement(pBase, &pFloat);
                              *pFloat++ = v.n.x;
                              *pFloat++ = v.n.y;
                              *pFloat++ = v.n.z;
                              break;
                        case Ogre::VES_DIFFUSE:
                              elem.baseVertexPointerToElement(pBase, &pFloat);
                              *pFloat++ = v.r;
                              *pFloat++ = v.g;
                              *pFloat++ = v.b;
                              *pFloat++ = v.a;
                              break;
                        case Ogre::VES_TEXTURE_COORDINATES:
                              elem.baseVertexPointerToElement(pBase, &pFloat);
                              ucoord = v.texcoords[iTexCoord].u;
                              vcoord = v.texcoords[iTexCoord].v;
                              *pFloat++ = ucoord;
                              *pFloat++ = vcoord;
                              iTexCoord++;
                              break;
                        }
                  }
                  pBase += vertexSize;
            }
            vbuf->unlock();
            return MS::kSuccess;
      }
      // Create mesh poses for an Ogre mesh
      MStatus Mesh::createOgrePoses(Ogre::MeshPtr pMesh,ParamList& params)
      {
            int i,j,k;
            if (params.useSharedGeom)
            {
                  // Read poses associated from all blendshapes associated to the shared geometry
                  for (i=0; i<m_sharedGeom.dagMap.size(); i++)
                  {
                        BlendShape* pBS = m_sharedGeom.dagMap[i].pBlendShape;
                        // Check if we have a blend shape associated to this subset of the shared geometry
                        if (pBS)
                        {
                              // Get all poses from current blend shape deformer
                              for (j=0; j<pBS->getPoses().size(); j++)
                              {
                                    // Get the pose
                                    pose* p = &(pBS->getPoses()[j]);
                                    if (p->name == "")
                                    {
                                          p->name = "pose";
                                          p->name += j;
                                    }
                                    // Create a new pose for the ogre mesh
                                    Ogre::Pose* pPose = pMesh->createPose(0,p->name.asChar());
                                    // Set the pose attributes
                                    for (k=0; k<p->offsets.size(); k++)
                                    {
                                          Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z);
                                          pPose->addVertex(p->offsets[k].index,offset);
                                    }
                              }
                        }
                  }
            }
            else
            {
                  // Get poses associated to the submeshes
                  for (i=0; i<m_submeshes.size(); i++)
                  {
                        BlendShape* pBS = m_submeshes[i]->m_pBlendShape;
                        // Check if this submesh has a blend shape deformer associated
                        if (pBS)
                        {
                              // Get all poses from current blend shape deformer
                              for (j=0; j<pBS->getPoses().size(); j++)
                              {
                                    // Get the pose
                                    pose* p = &(pBS->getPoses()[j]);
                                    if (p->name == "")
                                    {
                                          p->name = "pose";
                                          p->name += j;
                                    }
                                    // Create a new pose for the ogre mesh
                                    Ogre::Pose* pPose = pMesh->createPose(p->index,p->name.asChar());
                                    // Set the pose attributes
                                    for (k=0; k<p->offsets.size(); k++)
                                    {
                                          Ogre::Vector3 offset(p->offsets[k].x,p->offsets[k].y,p->offsets[k].z);
                                          pPose->addVertex(p->offsets[k].index,offset);
                                    }
                              }
                        }
                  }
            }
            return MS::kSuccess;
      }
      // Create vertex animations for an Ogre mesh
      MStatus Mesh::createOgreVertexAnimations(Ogre::MeshPtr pMesh,ParamList& params)
      {
            int i,j,k;
            std::cout << "pippo\n";
            std::cout.flush();
            // Read the list of vertex animation clips
            for (i=0; i<m_vertexClips.size(); i++)
            {
                  // Create a new animation
                  Ogre::Animation* pAnimation = pMesh->createAnimation(m_vertexClips[i].m_name.asChar(),m_vertexClips[i].m_length);
                  // Create all tracks for current animation
                  for (j=0; j<m_vertexClips[i].m_tracks.size(); j++)
                  {
                        Track* t = &(m_vertexClips[i].m_tracks[j]);
                        // Create a new track
                        Ogre::VertexAnimationTrack* pTrack;
                        if (t->m_target == T_MESH)
                              pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_MORPH);
                        else
                        {
                              pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData,
                                    Ogre::VAT_MORPH);
                        }
                        // Create keyframes for current track
                        for (k=0; k<t->m_vertexKeyframes.size(); k++)
                        {
                              // Create a new keyframe
                              Ogre::VertexMorphKeyFrame* pKeyframe = pTrack->createVertexMorphKeyFrame(t->m_vertexKeyframes[k].time);
                              // Create vertex buffer for current keyframe
                              Ogre::HardwareVertexBufferSharedPtr pBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
                                    Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
                                    t->m_vertexKeyframes[k].positions.size(),
                                    Ogre::HardwareBuffer::HBU_STATIC, true);
                              float* pFloat = static_cast<float*>(pBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
                              // Fill the vertex buffer with vertex positions
                              int vi;
                              std::vector<vertexPosition>& positions = t->m_vertexKeyframes[k].positions;
                              for (vi=0; vi<positions.size(); vi++)
                              {
                                    *pFloat++ = static_cast<float>(positions[vi].x);
                                    *pFloat++ = static_cast<float>(positions[vi].y);
                                    *pFloat++ = static_cast<float>(positions[vi].z);
                              }
                              // Unlock vertex buffer
                              pBuffer->unlock();
                              // Set vertex buffer for current keyframe
                              pKeyframe->setVertexBuffer(pBuffer);
                        }
                  }
            }
            return MS::kSuccess;
      }
      // Create pose animations for an Ogre mesh
      MStatus Mesh::createOgrePoseAnimations(Ogre::MeshPtr pMesh,ParamList& params)
      {
            int i,j,k;
            // Get all loaded blend shape clips
            for (i=0; i<m_BSClips.size(); i++)
            {
                  // Create a new animation for each clip
                  Ogre::Animation* pAnimation = pMesh->createAnimation(m_BSClips[i].m_name.asChar(),m_BSClips[i].m_length);
                  // Create animation tracks for this animation
                  for (j=0; j<m_BSClips[i].m_tracks.size(); j++)
                  {
                        Track* t = &m_BSClips[i].m_tracks[j];
                        // Create a new track
                        Ogre::VertexAnimationTrack* pTrack;
                        if (t->m_target == T_MESH)
                              pTrack = pAnimation->createVertexTrack(0,pMesh->sharedVertexData,Ogre::VAT_POSE);
                        else
                        {
                              pTrack = pAnimation->createVertexTrack(t->m_index+1,pMesh->getSubMesh(t->m_index)->vertexData,
                                    Ogre::VAT_POSE);
                        }
                        // Create keyframes for current track
                        for (k=0; k<t->m_vertexKeyframes.size(); k++)
                        {
                              Ogre::VertexPoseKeyFrame* pKeyframe = pTrack->createVertexPoseKeyFrame(t->m_vertexKeyframes[k].time);
                              int pri;
                              for (pri=0; pri<t->m_vertexKeyframes[k].poserefs.size(); pri++)
                              {
                                    vertexPoseRef* pr = &t->m_vertexKeyframes[k].poserefs[pri];
                                    pKeyframe->addPoseReference(pr->poseIndex,pr->poseWeight);
                              }
                        }
                  }
            }
            return MS::kSuccess;
      }

}; //end of namespace

Generated by  Doxygen 1.6.0   Back to index