#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ATPExport.h" //Vertex struct that holds all info about a vertex struct vertex { double points[3]; double UV[2]; double normals[3]; vector influences; //Overloaded == operator for compairing vertexes bool operator ==(const vertex &v1) const { if(points[0] == v1.points[0] && points[1] == v1.points[1] && points[2] == v1.points[2] && UV[0] == v1.UV[0] && UV[1] == v1.UV[1] && normals[0] == v1.normals[0] && normals[1] == v1.normals[1] && normals[2] == v1.normals[2]) return true; else return false; } }; struct Triangle { int index[3]; }; /////////////////////////////////////////////////////////////////////////////// // getTextureNamesFromMesh() // // Gets the texture names from all the sets of a mesh. // // Input: mesh - mesh to get from // names - returned textures // count - returned number of textures /////////////////////////////////////////////////////////////////////////////// void getTextureNamesFromMesh( MFnMesh &mesh, MStringArray &names, unsigned &count ) { // local vars MStatus status; MObjectArray meshSets; MObjectArray meshComps; unsigned meshSetCount = 0; // get sets & components from mesh mesh.getConnectedSetsAndMembers( 0, meshSets, meshComps, true ); meshSetCount = meshSets.length(); if ( meshSetCount > 1 ) meshSetCount--; // init in-vars names.clear(); count = 0; // get info from sets for ( unsigned i = 0; i < meshSetCount; i++ ) { MObject set = meshSets[i]; MObject comp = meshComps[i]; MFnSet fnSet( set ); // make sure we have a polygon set MItMeshPolygon meshSetIterator( mesh.dagPath(), comp, &status ); if ( !status ) continue; // MFnDependencyNode fnNode( set ); MPlugArray connectedPlugs; // get shader plug MPlug shaderPlug = fnNode.findPlug( "surfaceShader", &status ); //_MAYA_ASSERT( status, MString( "Failed to get shader plug for: " + mesh.partialPathName() ) ); if ( !status ) continue; if ( shaderPlug.isNull() ) continue; // get shader node shaderPlug.connectedTo( connectedPlugs, true, false, &status ); //_MAYA_ASSERT( status, MString( "Failed to get shader node for: " + mesh.partialPathName() ) ); if ( !status ) continue; if ( connectedPlugs.length() != 1 ) continue; // get color plug MPlug colorPlug = MFnDependencyNode( connectedPlugs[0].node() ).findPlug("color", &status); //_MAYA_ASSERT( status, MString( "Failed to get color plug for: " + mesh.partialPathName() ) ); if ( !status ) continue; // get iterator for traversing our color plug MItDependencyGraph itDG( colorPlug, MFn::kFileTexture, MItDependencyGraph::kUpstream, MItDependencyGraph::kBreadthFirst, MItDependencyGraph::kNodeLevel, &status ); if ( !status ) continue; // disable automatic pruning so that we can locate a specific plug itDG.disablePruningOnFilter(); if ( itDG.isDone() ) continue; // get file plug MObject textureNode = itDG.thisNode(); MPlug filePlug = MFnDependencyNode( textureNode ).findPlug( "fileTextureName" ); MString textureName( "" ); // log texture name if ( filePlug.getValue( textureName ) && textureName != "" ) { names.append( textureName ); count++; } } } /////////////////////////////////////////////////////////////////////////////// // writer() // // Gets the texture names from all the sets of a mesh. // // Input: file - object file we are trying to open // optionsString - optional options // FileAccessMode - tells us the file access mode /////////////////////////////////////////////////////////////////////////////// MStatus ATPExport::writer(const MFileObject &file, const MString &optionsString, MPxFileTranslator::FileAccessMode mode) { //Clear out the current animation tracks tracks.clear(); //Create an outstream ofstream outfile; char buffer[128]; //Create local vectors to hold data vector MasterVerts; vector Indexes; bool PointIn = false; bool NormalIn = false; bool VertIn = false; //TODO: Export Model sprintf_s(buffer, 128, "%s", file.name().asChar()); outfile.open(buffer); //Find the mesh node MItDag itDag(MItDag::kDepthFirst, MFn::kMesh); MDagPath DPath; itDag.getPath(DPath); MFnMesh mesh(DPath); outfile << "\n"; outfile << "\n"; //Get the mesh name sprintf_s(buffer, 128, "\n", mesh.name().asChar()); outfile << buffer; //Get the mesh path sprintf_s(buffer, 128, "%s\n", mesh.fullPathName().asChar()); outfile << buffer; //Itterate through the bones MItDag itDag2(MItDag::kDepthFirst, MFn::kJoint); MDagPath OrigianlPath; itDag2.getPath(OrigianlPath); //Make the root node RootNode = new SkeletonNode(); //Give the bones their name and transform for(;!itDag2.isDone(); itDag2.next()) { MFnDagNode Node(itDag2.item()); Bone TempBone; strcpy_s(TempBone.Name, 128, Node.partialPathName().asChar()); TempBone.xForm = Node.transformationMatrix(); AllBones.push_back(TempBone); } MFnDagNode OrigianlObject(OrigianlPath); //Find the root node while(true) { //Any Parents? No == root Yes == (is it a joint? if(OrigianlObject.parentCount() > 0) { bool bFound = false; for(unsigned int i = 0; i< OrigianlObject.parentCount(); ++i) { MObject obj = OrigianlObject.parent(i); if(obj.apiType() == MFn::kJoint) { OrigianlObject.setObject(obj); OrigianlObject.getPath(OrigianlPath); bFound = true; break; } } if(bFound == false) { break; } } else break; } //Find the root nodes index for(unsigned int i = 0; i < AllBones.size(); ++i) { if(strcmp(OrigianlPath.fullPathName().asChar(), AllBones[i].Name) == 0) { RootNode->BoneIndex = i; break; } } //Build the heirarchy for all of the bones starting from the root BuildHeirarchy(OrigianlPath, RootNode); //Itterate through all of the meshes for(;!itDag.isDone(); itDag.next()) { MDagPath DPath; itDag.getPath(DPath); MFnMesh mesh(DPath); //Assume control of the mesh node if(mesh.isIntermediateObject()) continue; //Get the mesh info <---- Work is here //Iterates through the mesh MItMeshPolygon itter(mesh.object()); //Set up temp cars vertex TempVertex; Triangle TempTriang; MPointArray TempPoints; MFloatVectorArray TempNormals; MFloatArray TempU; MFloatArray TempV; //Pull out the points, normals, and uv's from the mesh mesh.getPoints(TempPoints); mesh.getNormals(TempNormals); mesh.getUVs(TempU, TempV); ExportSkin(mesh.object()); ExportAnimation(); //Itter though the polys of the mesh for(;!itter.isDone(); itter.next()) { //3 points to a vert for(int i = 0; i < 3; ++i) { //Clear out the old vertex TempVertex.influences.clear(); int index; //Grab the index into the vertex list and put it into a temp vertex index = itter.vertexIndex(i); TempVertex.points[0] = TempPoints[index].x; TempVertex.points[1] = TempPoints[index].y; TempVertex.points[2] = TempPoints[index].z; //Grab the index into the Normal list and put it into a temp vertex index = itter.normalIndex(i); TempVertex.normals[0] = TempNormals[index].x; TempVertex.normals[1] = TempNormals[index].y; TempVertex.normals[2] = TempNormals[index].z; //Grab the index into the UV list and put it into a temp vertex itter.getUVIndex(i, index); TempVertex.UV[0] = TempU[index]; TempVertex.UV[1] = TempV[index]; Influence TempInfluence; index = itter.vertexIndex(i); //Grab the index into the Weight list and put it into a temp vertex for(unsigned int x = 0; x < skinningData.influences[index].size(); ++x) { TempInfluence.index = skinningData.influences[index][x].index; TempInfluence.weight = skinningData.influences[index][x].weight; TempVertex.influences.push_back(TempInfluence); } //Check to see if the vert is already in the list for(unsigned int j = 0; j < MasterVerts.size(); ++j) { //If it is push the index if(TempVertex == MasterVerts[j]) { VertIn = true; TempTriang.index[i] = j; } } //If its not add it to our master vertex list if(VertIn == true) VertIn = false; else { TempTriang.index[i] = (int)MasterVerts.size(); MasterVerts.push_back(TempVertex); } } Indexes.push_back(TempTriang); } } //Vert and Poly count sprintf_s(buffer, 128, "%i\n", MasterVerts.size()); outfile << buffer; sprintf_s(buffer, 128, "%i\n", mesh.numPolygons()); outfile << buffer; //Texture Name //Do some crazy string parsing or the name of the mesh MStringArray TexturName; unsigned int count = 0; char TxBuffer[1000]; getTextureNamesFromMesh(mesh, TexturName, count); strcpy_s(TxBuffer, 1000, TexturName[0].asChar()); string MyString = TxBuffer; int x = (int)MyString.find_last_of('/'); MString MStringMe(TxBuffer); int y = (int)MyString.length() + 1; MStringMe = MStringMe.substring(x + 1, y); char WeeeeBuffer[128]; strcpy_s(WeeeeBuffer, 128, MStringMe.asChar()); sprintf_s(TxBuffer, 1000, "%s\n", WeeeeBuffer); outfile << TxBuffer; outfile << "\n\n\n"; for(unsigned int i = 0; i < MasterVerts.size(); ++i) { //Print Vert Id sprintf_s(buffer, 128, "\n", i); outfile << buffer; //Print points sprintf_s(buffer, 128, "%f\n", MasterVerts[i].points[0]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].points[1]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].points[2]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].normals[0]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].normals[1]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].normals[2]); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].UV[0]); outfile << buffer; sprintf_s(buffer, 128, "%f", MasterVerts[i].UV[1]); outfile << buffer; //Print influences outfile << "\n\n"; for(unsigned int j = 0; j < MasterVerts[i].influences.size(); ++j) { outfile << "\n"; sprintf_s(buffer, 128, "%i\n", MasterVerts[i].influences[j].index); outfile << buffer; sprintf_s(buffer, 128, "%f\n", MasterVerts[i].influences[j].weight); outfile << buffer; outfile << "\n"; } outfile << "\n"; outfile << "\n\n"; } outfile << "\n\n"; outfile << "\n\n"; //Print teh indexes for(unsigned int i = 0; i < Indexes.size(); ++i) { outfile << "\n"; sprintf_s(buffer, 128, "%i\n", Indexes[i].index[0]); outfile << buffer; sprintf_s(buffer, 128, "%i\n", Indexes[i].index[1]); outfile << buffer; sprintf_s(buffer, 128, "%i\n", Indexes[i].index[2]); outfile << buffer; outfile << "\n\n"; } outfile << "\n\n"; //Print out the bone name and its index outfile << "\n\n"; int jlhh = AllBones.size(); for(unsigned int i = 0; i < AllBones.size(); ++i) { sprintf_s(buffer, 128, "\n", i); outfile << buffer; sprintf_s(buffer, 128, "%s\n", AllBones[i].Name); outfile << buffer; outfile << "\n\n"; } outfile << "\n\n"; outfile << "\n\n"; outfile << "\n\n"; //Print out the bones RootNode->printed = false; HelpPrintBones(RootNode, outfile); outfile << "\n"; sprintf_s(buffer, 128, "\n\n", m_FullTime.as(MTime::kMilliseconds)); outfile << buffer; //Print out the frames for(int i = 0; i < AllBones.size(); ++i) { for(map::const_iterator it = tracks.begin(); it != tracks.end(); ++it) { if(strcmp(it->first.c_str(), AllBones[i].Name) == 0) { SortedFrames TempFrame; TempFrame.first = AllBones[i].Name; TempFrame.second = it->second; MySortedList.push_back(TempFrame); } } } //Print out the keyframes for(int i = 0; i < MySortedList.size(); ++i) { outfile << "\n\n"; sprintf_s(buffer, 128, "%s\n\n", i, MySortedList[i].first.c_str()); outfile << buffer; for(int x = 0; x < MySortedList[i].second.size(); ++x) { sprintf_s(buffer, 128, "\n", x); outfile << buffer; double MyTime = MySortedList[i].second[x].time.as(MTime::kMilliseconds);//it->second[i].time.as(MTime::kMilliseconds); sprintf_s(buffer, 128, "\n\n", MyTime); outfile << buffer; outfile << "\n"; for(int j = 0; j < 4; ++j) { double Transform[4][4]; MySortedList[i].second[x].transformation.get(Transform); sprintf_s(buffer, 128, " %f %f %f %f \n", j + 1, Transform[j][0], Transform[j][1], Transform[j][2], Transform[j][3], j + 1); outfile << buffer; } outfile << "\n"; outfile << "\n\n"; } outfile << "\n\n"; } outfile << ""; outfile << "\n"; return MS::kSuccess; } MStatus ATPExport::ExportSkin(MObject &obj) { MFnSkinCluster skinCluster; MStatus status; MFnMesh meshNode(obj); //Create a plug to find the node MPlug inMeshPlug = meshNode.findPlug("inMesh", &status); if(status == MS::kSuccess && inMeshPlug.isConnected() ) { //Make an itter to go through the skeleton node MItDependencyGraph dgIt(inMeshPlug, MFn::kInvalid, MItDependencyGraph::kUpstream, MItDependencyGraph::kDepthFirst, MItDependencyGraph::kPlugLevel, &status); //Itter till we find the node for(;!dgIt.isDone(); dgIt.next() ) { if (dgIt.thisNode().apiType() == MFn::kSkinClusterFilter) { skinCluster.setObject(dgIt.thisNode()); break; } } } MDagPath Path; meshNode.getPath(Path); MDagPathArray influenceObjectPaths; skinCluster.influenceObjects(influenceObjectPaths, &status); char Buffer[128]; //Get the names of the influences for(unsigned int i = 0; i < influenceObjectPaths.length(); ++i) { strcpy_s(Buffer, 128, influenceObjectPaths[i].partialPathName().asChar()); skinningData.jointNames.push_back(Buffer); } unsigned int myCounter = 0; MItGeometry geoIt(obj); //Itter through the geometry of the obj passed in for(;!geoIt.isDone(); geoIt.next()) { MObject comp = geoIt.component(); MFloatArray WeightArray; unsigned int numInfluences; //Get the weights of this bone skinCluster.getWeights(Path, comp, WeightArray, numInfluences); int x = WeightArray.length(); vector TempInfluence; //Loop through to find the weights that are usable for(unsigned int j = 0; j < WeightArray.length(); ++j) { if(WeightArray[j] > 0.001f) { Influence influence; influence.index = j; influence.weight = WeightArray[j]; TempInfluence.push_back(influence); } } skinningData.influences.push_back(TempInfluence); } return status; } void ATPExport::BuildHeirarchy(MDagPath path, SkeletonNode *CurrentNode) { char buffer[128]; unsigned int i = 0; strcpy_s(buffer, 128, path.partialPathName().asChar()); //Find the index for the node that was passed in for(; i < AllBones.size(); ++i) { if(strcmp(path.partialPathName().asChar(), AllBones[i].Name) == 0) break; } //Set the bones index CurrentNode->BoneIndex = i; for(unsigned int j = 0; j < path.childCount(); ++j) { //Check and see if the next item in the list is actually a bone if(path.child(j).hasFn(MFn::kJoint)) { //Make a temp node and call the function again on it. Then push it in as a child SkeletonNode *TempNode = new SkeletonNode; MFnDagNode Node(path.child(j)); MDagPath Path; Node.getPath(Path); BuildHeirarchy(Path, TempNode); CurrentNode->children.push_back(TempNode); } } } void ATPExport::HelpPrintBones(SkeletonNode *CurrentNode, ofstream &outfile) { //Check and see if the childrens list has anything in it if(CurrentNode->children.size() != 0) { for(unsigned int i = 0; i < CurrentNode->children.size(); ++i) { //Set that this bone hasn't been printed yet CurrentNode->children[i]->printed = false; if(CurrentNode->printed == false) { char buffer[128]; outfile << "\n"; sprintf_s(buffer, 128, "%s\n", CurrentNode->BoneIndex, AllBones[CurrentNode->BoneIndex].Name); outfile << buffer; outfile << "\n"; //Print the transform data for(int j = 0; j < 4; ++j) { double Transform[4][4]; AllBones[CurrentNode->BoneIndex].xForm.get(Transform); sprintf_s(buffer, 128, " %f %f %f %f \n", j + 1, Transform[j][0], Transform[j][1], Transform[j][2], Transform[j][3], j + 1); outfile << buffer; } outfile << "\n"; outfile << "\n"; //Print out the children of this node for(unsigned int j = 0; j < CurrentNode->children.size(); ++j) { int x = CurrentNode->children[j]->BoneIndex; sprintf_s(buffer, 128, "%s\n", CurrentNode->children[j]->BoneIndex, AllBones[CurrentNode->children[j]->BoneIndex].Name); outfile << buffer; } outfile << "\n"; outfile << "\n"; //Say we've been printed CurrentNode->printed = true; } //Call print on the first child HelpPrintBones(CurrentNode->children[i], outfile); } } else { //If we have no children just print this bone out and contiune char buffer[128]; outfile << "\n"; sprintf_s(buffer, 128, "%s\n", CurrentNode->BoneIndex, AllBones[CurrentNode->BoneIndex].Name); outfile << buffer; outfile << "\n"; for(int j = 0; j < 4; ++j) { double Transform[4][4]; AllBones[CurrentNode->BoneIndex].xForm.get(Transform); sprintf_s(buffer, 128, " %f %f %f %f \n", j + 1, Transform[j][0], Transform[j][1], Transform[j][2], Transform[j][3], j + 1); outfile << buffer; } outfile << "\n"; outfile << "\n"; outfile << "\n"; outfile << "\n"; } } void ATPExport::ExportAnimation() { MStatus status; MItDag dagIt(MItDag::kDepthFirst, MFn::kJoint, &status); set jointTimes; MTime originalTime; int totalcount = 0; bool breakout = false; for(; !dagIt.isDone(); dagIt.next()) { MDagPath jointPath; dagIt.getPath(jointPath); if(!MAnimUtil::isAnimated(jointPath)) { continue; } bonePaths.push_back(jointPath); MPlugArray animatedPlugs; MAnimUtil::findAnimatedPlugs(jointPath, animatedPlugs); for(unsigned int i = 0; i < animatedPlugs.length(); ++i)//animatedPlugs.length() { MObjectArray curves; MAnimUtil::findAnimation(animatedPlugs[i], curves); for(unsigned int j = 0; j < curves.length(); ++j) { MFnAnimCurve curve(curves[j]); for(unsigned int k = 0; k < curve.numKeys(); ++k) { jointTimes.insert(curve.time(k)); } } } for(unsigned int i = 0; i < 1; ++i) { MDagPath jointPath = bonePaths[i]; for(set::const_iterator it = jointTimes.begin(); it != jointTimes.end(); ++it) { TimesToBonesMap.insert(TimesToBones::value_type(*it, totalcount)); } } originalTime = MAnimControl::currentTime(); MTime mayaTime = originalTime; string Name; int capin = 0; for(TimesToBones::const_iterator it = TimesToBonesMap.begin(); it != TimesToBonesMap.end(); ++it) { if(mayaTime != it->first) { MAnimControl::setCurrentTime(it->first); mayaTime = it->first; } Track& CurrentTrack = tracks[AllBones[it->second].Name]; MDagPath currentPath = bonePaths[it->second]; Keyframe newFrame; newFrame.time = it->first; double time = newFrame.time.as(MTime::kMilliseconds); MFnTransform transform(currentPath); newFrame.transformation = transform.transformation().asMatrix(); CurrentTrack.push_back(newFrame); int x = it->second; Name = AllBones[it->second].Name; //AllBones[it->second].MyKeyTrack.push_back(newFrame); //capin++; //if(capin == 28) //{ // capin = 0; // continue; //} } TimesToBonesMap.clear(); jointTimes.clear(); totalcount++; } MAnimControl::setPlaybackMode(MAnimControl::kPlaybackOnce); m_FullTime = MAnimControl::animationEndTime(); MAnimControl::setCurrentTime(originalTime); }