Scene3DMesh* SGMExporter::ConvertMesh(IGameNode* meshNode) { std::string meshNodeName = StringUtils::ToNarrow(meshNode->GetName()); Log::LogT("exporting node '%s'", meshNodeName.c_str()); IGameMesh *gMesh = (IGameMesh*)meshNode ->GetIGameObject(); assert(gMesh); if (!gMesh ->InitializeData()) { Log::LogT("error: couldnt initialize data, skipping node"); return NULL; } if (!gMesh->IsObjectSkinned()) { Log::LogT("Mesh '%s' is not skinned", meshNodeName.c_str()); meshNode->ReleaseIGameObject(); return NULL; } else Log::LogT("Mesh '%s' is skinned", meshNodeName.c_str()); Scene3DMesh *mesh = new Scene3DMesh(); mesh->id = meshNode->GetNodeID(); mesh->name = StringUtils::ToNarrow(meshNode->GetName()); CollectProperties(mesh, gMesh); IGameMaterial *mat = meshNode ->GetNodeMaterial(); if (mat != NULL) mesh->materialName = StringUtils::ToNarrow(mat->GetMaterialName()); IGameSkin* skin = gMesh->GetIGameSkin(); for (int i = 0; i < skin->GetTotalSkinBoneCount(); i++) mesh->bonesIds.push_back(skin->GetIGameBone(i)->GetNodeID()); for (int i = 0; i < gMesh ->GetNumberOfFaces(); i++) ExtractVertices(skin, gMesh ->GetFace(i), gMesh, mesh->vertices); Log::LogT("Min bones = %d, max bones = %d", dbgMinBonesCount, dbgMaxBonesCount); meshNode ->ReleaseIGameObject(); return mesh; }
//---------------------------------------------------------------------------------- bool Helper_ProcessFace(IGameMesh * gM, unsigned int Index, const AffineParts & PRS, const Matrix3 & world_to_obj, MatFaceMapType & matface_map, TriMapType & tri_map, unsigned int & MaxFaceIdx) { FaceEx *pFace = gM->GetFace(Index); IGameMaterial *pIGMat = gM->GetMaterialFromFace(Index); bool HasTexVerts = gM->GetNumberOfTexVerts() ? true : false; bool HasCVerts = gM->GetNumberOfColorVerts() ? true : false; unsigned int smg_id = pFace->smGrp; // smooth group unsigned int mat_id = ExporterMAX::GetExporter()->FindMaterialIdx(pIGMat); IGameSkin *skin = NULL; const int numMod = gM->GetNumModifiers(); if (numMod > 0) { for (int i = 0; i < numMod; i++) // check for skin modifier { IGameModifier *pM = gM->GetIGameModifier(i); if (pM->IsSkin()) { skin = (IGameSkin*)pM; // skin modifier } } } mesh_opt * m_opt = NULL; // lets sort by material and find the corresponding mesh_opt MatFaceMapIt it_matfacemap = matface_map.find(mat_id); if (it_matfacemap == matface_map.end()) // no corresponding mesh, allocate new face holder { m_opt = new mesh_opt(); matface_map.insert(MatFaceMapPair(mat_id, m_opt)); } else { m_opt = (*it_matfacemap).second; } for (int j = 0; j < 3; ++j) // build the face { vert_opt face; unsigned int idx; unsigned int ori_face_idx = pFace->vert[j]; // get index into the vertex array unsigned int face_idx = ori_face_idx; bool create_face = false; // build the face as expected face.smg_id = smg_id; // smooth group if (HasTexVerts) { idx = pFace->texCoord[j]; // get index into the standard mapping channel if (idx != BAD_IDX) { face.t.x = gM->GetTexVertex(idx).x; face.t.y = gM->GetTexVertex(idx).y; } } if (HasCVerts) { idx = pFace->color[j]; face.c.x = gM->GetColorVertex(idx).x; // get vertex color face.c.y = gM->GetColorVertex(idx).y; face.c.z = gM->GetColorVertex(idx).z; face.c.w = 1.f; } else { face.c = Vector4f(1.f, 1.f, 1.f, 1.f); } Tab<int> mapNums = gM->GetActiveMapChannelNum(); face.num_tmaps = mapNums.Count(); if (face.num_tmaps) { face.tmaps = new Vector[face.num_tmaps]; for (size_t k = 0; k < face.num_tmaps; ++k) { unsigned long mapfaceidx[3]; gM->GetMapFaceIndex(mapNums[k], Index, &mapfaceidx[0]); idx = mapfaceidx[j]; face.tmaps[k].x = gM->GetMapVertex(mapNums[k], idx).x; face.tmaps[k].y = gM->GetMapVertex(mapNums[k], idx).y; face.tmaps[k].z = gM->GetMapVertex(mapNums[k], idx).z; } } // try to find in origin array FaceMapIt it_face_map = m_opt->face_map.find(face_idx); // get face map iter if (it_face_map == m_opt->face_map.end()) // if not find such create anyway { create_face = true; } else { if (is_matching((*it_face_map).second, face) == false) // check find vertex not matching { bool found = false; // process vertex multi map std::pair<FaceMMapIt,FaceMMapIt> pair_mmap = m_opt->face_mmap.equal_range(ori_face_idx); FaceMMapIt it_face_mmap = pair_mmap.first; while (it_face_mmap != pair_mmap.second && found == false) { idxvert_opt & idxface = (*it_face_mmap).second; if (is_matching(idxface.face, face)) { face_idx = idxface.new_idx; found = true; } ++it_face_mmap; } if (found == false) { create_face = true; ++MaxFaceIdx; // increment max index and face_idx = MaxFaceIdx; // set index is out of bounds of origin 3DMax's index range } } } if (create_face) { if (skin) { std::vector<w_offset> w_offsets; for (int k = 0; k < skin->GetNumberOfBones(ori_face_idx); ++k) { /* if (skin->GetWeight(ori_face_idx, k) > m_eps) { w_offset w; w.weight = skin->GetWeight(ori_face_idx, k); _BoneObject * Bone = ExporterMAX::GetExporter()->Skeleton.AddMaxBone(skin->GetIGameBone(ori_face_idx, k), skin->GetIGameBone(ori_face_idx, k)->GetNodeID()); assert(Bone != NULL); w.bone_id = Bone->GetID(); w_offsets.push_back(w); }*/ } // std::sort(w_offsets.begin(), w_offsets.end(), heavier); int ILeft = 0; for (size_t l = 0; l < w_offsets.size() && l < 4; ++l, ++ILeft) { w_offset & w = w_offsets[l]; face.weights[l] = w.weight; face.bones[l] = w.bone_id; } for (; ILeft < 4; ++ILeft) { face.weights[ILeft] = 0.f; face.bones[ILeft] = BAD_IDX; } // check for valid weights... float w_sum = 0.f; for (int l = 0; l < 4; ++l) { w_sum += face.weights[l]; } if ((w_sum < m_one - m_eps) || (w_sum > m_one + m_eps)) { for (int l = 0; l < 4; ++l) // renormalizing... face.weights[l] /= w_sum; } } Point3 v_world = gM->GetVertex(ori_face_idx); Point3 v_obj = v_world; // * world_to_obj; face.v.x = v_obj.x; // * PRS.k.x * PRS.f; face.v.y = v_obj.z; // * PRS.k.z * PRS.f; face.v.z = v_obj.y; // * PRS.k.y * PRS.f; // add the vertex and store its new idx face.face_idx = m_opt->count; m_opt->face_map.insert(FaceMapPair(face_idx, face)); if (ori_face_idx != face_idx) // store the newly created and duplicated independently { idxvert_opt idxface(face_idx, face);// store new face m_opt->face_mmap.insert(FaceMMapPair(ori_face_idx, idxface)); // but store key as a original } m_opt->count++; } // add the face indices... TriMapIt it = tri_map.find(mat_id); if (it != tri_map.end()) { (*it).second->push_back(face_idx); } else { IdxType * idx_type = new IdxType; idx_type->push_back(face_idx); tri_map.insert(TriMapPair(mat_id, idx_type)); } } return true; }
int MaxExporter::DoExport(const TCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options) { /*if(!suppressPrompts) DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), MaxExporterOptionsDlgProc, (LPARAM)this);*/ #pragma message(TODO("return TRUE If the file is exported properly")) Node::s_nextID = 1; ofstream myFile; myFile.open("DebugExporter.txt"); wstring wFileName( name ); string fileName( wFileName.begin(), wFileName.end() ); //f= fopen( fileName.c_str(),"wb"); BinaryFile = loadSave( fileName.c_str() ); //BinaryFile.saveInt( 5 ); //BinaryFile.close(); myFile << "Start Export\n"; IGameScene* gameScene = GetIGameInterface(); gameScene->InitialiseIGame(); int nodeCount = gameScene->GetTopLevelNodeCount(); myFile << "Number of top level nodes: " << nodeCount << "\n"; //get all of the materials for( int nodeNumber = 0; nodeNumber < nodeCount; ++nodeNumber) { IGameNode* gameNode = gameScene->GetTopLevelNode( nodeNumber ); Node* myNode = new Node( gameNode ); m_NodeList.push_back( myNode ); findFaces( myNode, myFile ); } myFile << "Number of materials\n"; myFile << m_materialSet.size() << "\n"; int totalBatches = 0; //myFile<< "Number of triangleBatchMaps: " << m_triangleBatchesPerNode.size() << "\n"; for( auto nodeIter = m_NodeList.begin(); nodeIter != m_NodeList.end(); ++nodeIter ) { std::map< IGameMaterial*, TriangleBatch* > triangleBatches = (*nodeIter)->m_triangleBatchesPerMaterial; myFile << "Invidiual triangleBatch size: " << triangleBatches.size() << "\n"; for( auto materialIter = m_materialSet.begin(); materialIter != m_materialSet.end(); ++materialIter ) { auto found = triangleBatches.find( * materialIter ); if( found != triangleBatches.end() ) { ++totalBatches; } } } BinaryFile.saveInt( m_NodeList.size() ); myFile << "Number of Nodes: " << m_NodeList.size() << "\n"; for( auto nodeIter = m_NodeList.begin(); nodeIter != m_NodeList.end(); ++nodeIter ) { std::map< IGameMaterial*, TriangleBatch* > triangleBatches = (*nodeIter)->m_triangleBatchesPerMaterial; std::map<IGameMaterial*, std::vector< NodeFace > > facesPerMaterial = (*nodeIter)->m_facesPerMaterial; IGameNode* currentNode = (*nodeIter)->m_gameNode; IGameNode* parentNode; GMatrix parentWTM; GMatrix toParentMatrix; GMatrix worldTM; GMatrix localTM; int time = gameScene->GetSceneStartTime(); for( ; time < gameScene->GetSceneEndTime(); time += 4800/30 ) { if( (*nodeIter)->m_parentID != 0 ) { myFile << "Trying to find parent... \n"; parentNode = (*nodeIter)->m_parent->m_gameNode; if( parentNode != nullptr ) { myFile << "Parent found \n"; parentWTM = parentNode->GetWorldTM( time ); toParentMatrix = parentWTM.Inverse(); worldTM = currentNode->GetWorldTM( time ) * toParentMatrix; } } else { worldTM = currentNode->GetWorldTM( time ); } (*nodeIter)->m_toParentMatrix.push_back( Matrix4x4( worldTM[0], worldTM[1], worldTM[2], worldTM[3] ) ); } localTM = currentNode->GetWorldTM().Inverse(); (*nodeIter)->m_worldToLocal = Matrix4x4( localTM[0], localTM[1], localTM[2], localTM[3] ); //Save the node BinaryFile.saveNode( *nodeIter, myFile ); BinaryFile.saveInt( (*nodeIter)->m_triangleBatchesPerMaterial.size() ); for( auto materialIter = m_materialSet.begin(); materialIter != m_materialSet.end(); ++materialIter ) { //Set the current material's VBO and IBO // IGameMaterial* currentMaterial = *materialIter; TriangleBatch* currentBatch = triangleBatches[ currentMaterial ]; GMatrix localTMNoTrans = localTM; localTMNoTrans.SetRow( 3, Point4( 0,0,0,1) ); if( currentBatch != nullptr ) { MaxMaterial* currentMaxMaterial = currentBatch->m_material; VBO* currentVBO = currentBatch->m_vbo; IBO* currentIBO = currentBatch->m_ibo; vector< NodeFace >& faceVector = facesPerMaterial.find( currentMaterial )->second; //Get texture materials and export them // if( currentMaterial != nullptr ) { int numOfTexMaps = currentMaterial->GetNumberOfTextureMaps(); myFile << "Number of texture maps: " << numOfTexMaps << "\n"; for( int i = 0; i < numOfTexMaps; ++i ) { IGameTextureMap* gameTextureMap = currentMaterial->GetIGameTextureMap( i ); if( gameTextureMap != nullptr && gameTextureMap->IsEntitySupported() ) { int stdMapSlot = gameTextureMap->GetStdMapSlot(); if( stdMapSlot == ID_DI ) { wstring wBitmapFileName; wBitmapFileName = gameTextureMap->GetBitmapFileName(); if( wBitmapFileName.size() > 0 ) { BitmapInfo bi( gameTextureMap->GetBitmapFileName() ); BMMGetFullFilename( &bi ); wBitmapFileName = bi.Name(); std::string fullBitmapFileName( wBitmapFileName.begin(), wBitmapFileName.end() ); if( fullBitmapFileName.size() > 0 ) { int lastSlash = fullBitmapFileName.find_last_of('\\') + 1; if( lastSlash != string::npos ) { const std::string bitmapFileName = fullBitmapFileName.substr( lastSlash ); wstring nameAsWString( name ); std::string nameAsString( nameAsWString.begin(), nameAsWString.end() ); const std::string extension = nameAsString.substr( 0, nameAsString.find_last_of('\\') + 1 ); std::string newFileName = extension; newFileName.append( bitmapFileName ); wstring wNewFileName(newFileName.begin(), newFileName.end()); if( CopyFile( wBitmapFileName.c_str(), wNewFileName.c_str(), false ) ) { if( stdMapSlot == ID_DI ) { currentMaxMaterial->m_diffuseTexture = bitmapFileName; currentMaxMaterial->bHasDiffuseTexture = true; } //BinaryFile.saveString( bitmapFileName ); } else { myFile << GetLastError() << "\n"; myFile << "copying the file FAILED.\n"; } } } } } } } } myFile<< "Number of faces for this material: " << faceVector.size() << "\n"; for( int face = 0; face < faceVector.size(); ++face ) { FaceEx* meshFace = faceVector[face].m_face; IGameMesh* gameMesh = faceVector[face].m_mesh; IGameSkin* gameSkin = gameMesh->GetIGameSkin(); int position, normal, color, texCoordinate, maxPosition; for( int i = 0; i < 3; ++i) { maxPosition = (int)meshFace->vert[i]; Point3 tempPos = gameMesh->GetVertex( maxPosition ); tempPos = tempPos * localTM; Vector3D positionVec3( tempPos.x, tempPos.y, tempPos.z ); position = currentVBO->insertPosition(positionVec3); normal = (int)meshFace->norm[i]; Point3 tempNormal = gameMesh->GetNormal( normal ); tempNormal = tempNormal * localTMNoTrans; tempNormal = tempNormal.Normalize(); Vector3D normalVec3( tempNormal.x, tempNormal.y, tempNormal.z ); normal = currentVBO->insertNormal(normalVec3); //IBO texCoordinate = (int)meshFace->texCoord[i]; Point2 tempTexCoord = gameMesh->GetTexVertex( texCoordinate ); Vector2 texCoordVec2( tempTexCoord.x, tempTexCoord.y ); texCoordinate = currentVBO->insertTexCoord(texCoordVec2); VertexIndex VI( position, normal, texCoordinate ); if( gameSkin != nullptr ) { int numberOfBones = gameSkin->GetNumberOfBones( maxPosition ); for( int boneIndex = 0; boneIndex < numberOfBones; ++boneIndex ) { float boneWeight = gameSkin->GetWeight( maxPosition, boneIndex ); IGameNode* bone = gameSkin->GetIGameBone( maxPosition, boneIndex ); myFile << "Bone node ID: " << bone->GetNodeID() << "\n"; int nodeIDForBone = m_boneIDToNodeID[ bone->GetNodeID() ]; myFile << "Node ID: " << nodeIDForBone << "\n"; VI.addBoneWeight( nodeIDForBone, boneWeight ); /*for( auto boneIter = m_NodeList.begin(); boneIter != m_NodeList.end(); ++boneIter ) { if( (*boneIter)->m_gameNode == bone ) { myFile << "Found the bone!\n"; } }*/ } VI.topBoneWeights(); } int vertIndex = currentVBO->insertVertex( VI ); currentIBO->addIndex( vertIndex ); } } BinaryFile.saveTriangleMesh( currentBatch, myFile ); } } } myFile.close(); for( int nodeNumber = 0; nodeNumber < nodeCount; ++nodeNumber) { IGameNode* gameNode = gameScene->GetTopLevelNode( nodeNumber ); if( gameNode != nullptr ) { tearDown( gameNode ); } } BinaryFile.close(); return TRUE; //return FALSE; }