void Unreal3DExport::Init() { // Init CheckCancel(); pScene = GetIGameInterface(); GetConversionManager()->SetUserCoordSystem(UnrealCoords); if( bExportSelected ) { Tab<INode*> selnodes;; for( int i=0; i<pInt->GetSelNodeCount(); ++i ) { INode* n = pInt->GetSelNode(i); selnodes.Append(1,&n); } if( !pScene->InitialiseIGame(selnodes,false) ) throw MAXException(GetString(IDS_ERR_IGAME)); } else { if( !pScene->InitialiseIGame() ) throw MAXException(GetString(IDS_ERR_IGAME)); } // Enumerate scene NodeCount = pScene->GetTotalNodeCount(); for( int i=0; i<pScene->GetTopLevelNodeCount(); ++i ) { IGameNode * n = pScene->GetTopLevelNode(i); ExportNode(n); } Progress += U3D_PROGRESS_ENUM; // Get animation info FrameStart = pScene->GetSceneStartTime() / pScene->GetSceneTicks(); FrameEnd = pScene->GetSceneEndTime() / pScene->GetSceneTicks(); FrameCount = FrameEnd - FrameStart+1; if( FrameCount <= 0 || FrameEnd < FrameStart ) { ProgressMsg.printf(GetString(IDS_ERR_FRAMERANGE),FrameStart,FrameEnd); throw MAXException(ProgressMsg.data()); } pScene->SetStaticFrame(FrameStart); }
void Unreal3DExport::WriteTracking() { Tab<Point3> Loc; Tab<Quat> Quat; Tab<Point3> Euler; Loc.SetCount(FrameCount); Quat.SetCount(FrameCount); Euler.SetCount(FrameCount); for( int n=0; n<TrackedNodes.Count(); ++n ) { IGameNode* node = TrackedNodes[n]; for( int t=0; t<FrameCount; ++t ) { // Progress CheckCancel(); // Set frame int curframe = FrameStart + t; pScene->SetStaticFrame(curframe); // Write tracking GMatrix objTM = node->GetWorldTM(); Loc[t] = objTM.Translation(); Quat[t] = objTM.Rotation(); float eu[3]; QuatToEuler(Quat[t],eu); Euler[t]=Point3(eu[0],eu[1],eu[2]); Euler[t] *= 180.0f/pi; eu[1] *= -1; EulerToQuat(eu,Quat[t],EULERTYPE_YXZ); } for( int t=0; t<FrameCount; ++t ) { _ftprintf( fLog, _T("%sLoc[%d]=(X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Loc[t].x, Loc[t].y, Loc[t].z ); } for( int t=0; t<FrameCount; ++t ) { _ftprintf( fLog, _T("%sQuat[%d]=(W=%f,X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Quat[t].w, Quat[t].x, Quat[t].y, Quat[t].z ); } for( int t=0; t<FrameCount; ++t ) { _ftprintf( fLog, _T("%sEuler[%d]=(X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Euler[t].x, Euler[t].y, Euler[t].z ); } } }
void Unreal3DExport::GetAnim() { // Export vertex animation int lastvert = 0; FMeshVert nullvert = FMeshVert(); Points.SetCount(VertsPerFrame*FrameCount,TRUE); for( int t=0; t<FrameCount; ++t ) { // Progress CheckCancel(); ProgressMsg.printf(GetString(IDS_INFO_ANIM),t+1,FrameCount); pInt->ProgressUpdate(Progress+((float)t/FrameCount*U3D_PROGRESS_ANIM), FALSE, ProgressMsg.data()); // Set frame int frameverts = 0; int curframe = FrameStart + t; pScene->SetStaticFrame(curframe); // Write mesh verts for( int n=0; n<Nodes.Count(); ++n ) { CheckCancel(); IGameMesh * mesh = (IGameMesh*)Nodes[n]->GetIGameObject(); if( mesh->InitializeData() ) { int vertcount = mesh->GetNumberOfVerts(); for( int i=0; i<vertcount; ++i ) { Point3 p; if( mesh->GetVertex(i,p) ) { Points[lastvert++] = p; } } frameverts += vertcount; } Nodes[n]->ReleaseIGameObject(); } // Check number of verts in this frame if( frameverts != VertsPerFrame ) { ProgressMsg.printf(GetString(IDS_ERR_NOVERTS),curframe,frameverts,VertsPerFrame); throw MAXException(ProgressMsg.data()); } } Progress += U3D_PROGRESS_ANIM; }
int DoExport( const MCHAR* name, ExpInterface* ei, Interface* i, BOOL suppressPrompts, DWORD options ) { UserCoord exporterCoord = { 1, // right-handed coordinate 1, // X axis goes right 2, // Y axis goes up 5, // Z axis goes out 1, // U goes right 0, // V goes up }; //// d3d setup //UserCoord exporterCoord = //{ // 0, // left-handed coordinate // 0, // X axis goes left // 2, // Y axis goes up // 5, // Z axis goes out // 1, // U goes right // 1, // V goes down //}; IGameScene* igScene = GetIGameInterface(); IGameConversionManager* cm = GetConversionManager(); cm->SetUserCoordSystem(exporterCoord); igScene->InitialiseIGame(); // export the very first frame igScene->SetStaticFrame( 0 ); RootExporter rootExporter; // go through all top nodes for ( int i=0; i<igScene->GetTopLevelNodeCount(); i++ ) { IGameNode* gameNode = igScene->GetTopLevelNode( i ); rootExporter.AddNode( gameNode ); } rootExporter.SaveToFile( name ); // done igScene->ReleaseIGame(); return TRUE; }
void Unreal3DExport::WriteScript() { // Write script file { fScript = _tfopen(ScriptFileName,_T("wb")); if( !fScript ) { ProgressMsg.printf(GetString(IDS_ERR_FSCRIPT),ScriptFileName); throw MAXException(ProgressMsg.data()); } TSTR buf; // Write class def _ftprintf( fScript, _T("class %s extends Object;\n\n"), FileName ); // write import _ftprintf( fScript, _T("#exec MESH IMPORT MESH=%s ANIVFILE=%s_a.3D DATAFILE=%s_d.3D \n"), FileName, FileName, FileName ); // write origin & rotation // TODO: figure out why it's incorrect without -1 Point3 porg = OptOffset * OptScale * -1; _ftprintf( fScript, _T("#exec MESH ORIGIN MESH=%s X=%f Y=%f Z=%f PITCH=%d YAW=%d ROLL=%d \n"), FileName, porg.x, porg.y, porg.z, (int)OptRot.x, (int)OptRot.y, (int)OptRot.z ); // write mesh scale Point3 psc( Point3(1.0f/OptScale.x,1.0f/OptScale.y,1.0f/OptScale.z)); _ftprintf( fScript, _T("#exec MESH SCALE MESH=%s X=%f Y=%f Z=%f \n"), FileName, psc.x, psc.y, psc.z ); // write meshmap _ftprintf( fScript, _T("#exec MESHMAP NEW MESHMA=P%s MESH=%smap \n"), FileName, FileName ); // write meshmap scale _ftprintf( fScript, _T("#exec MESHMAP SCALE MESHMAP=%s X=%f Y=%f Z=%f \n"), FileName, psc.x, psc.y, psc.z ); // write sequence _ftprintf( fScript, _T("#exec MESH SEQUENCE MESH=%s SEQ=%s STARTFRAME=%d NUMFRAMES=%d \n"), FileName, _T("All"), 0, FrameCount-1 ); // Get World NoteTrack ReferenceTarget *rtscene = pInt->GetScenePointer(); for( int t=0; t<rtscene->NumNoteTracks(); ++t ) { DefNoteTrack* notetrack = static_cast<DefNoteTrack*>(rtscene->GetNoteTrack(t)); for( int k=0; k<notetrack->keys.Count(); ++k ) { NoteKey* notekey = notetrack->keys[k]; TSTR text = notekey->note; int notetime = notekey->time / pScene->GetSceneTicks(); while( !text.isNull() ) { TSTR cmd = SplitStr(text,_T('\n')); if( MatchPattern(cmd,TSTR(_T("a *")),TRUE) ) { SplitStr(cmd,_T(' ')); TSTR seq = SplitStr(cmd,_T(' ')); int end = _ttoi(SplitStr(cmd,_T(' ')));; TSTR rate = SplitStr(cmd,_T(' ')); TSTR group = SplitStr(cmd,_T(' ')); if( seq.isNull() ) { ProgressMsg.printf(_T("Missing animation name in notekey #%d"),notetime); throw MAXException(ProgressMsg.data()); } if( end <= notetime ) { ProgressMsg.printf(_T("Invalid animation endframe (%d) in notekey #%d"),end,notetime); throw MAXException(ProgressMsg.data()); } int startframe = notetime; int numframes = end - notetime; buf.printf( _T("#exec MESH SEQUENCE MESH=%s SEQ=%s STARTFRAME=%d NUMFRAMES=%d"), FileName, seq, notetime, numframes ); if( !rate.isNull() ) buf.printf( _T("%s RATE=%f"), buf, rate ); if( !group.isNull() ) buf.printf( _T("%s GROUP=%f"), buf, rate ); SeqName = seq; SeqFrame = startframe; buf.printf( _T("%s \n"), buf ); _fputts( buf, fScript ); } else if( MatchPattern(cmd,TSTR(_T("n *")),TRUE) ) { SplitStr(cmd,_T(' ')); TSTR func = SplitStr(cmd,_T(' ')); TSTR time = SplitStr(cmd,_T(' ')); if( func.isNull() ) { ProgressMsg.printf(_T("Missing notify name in notekey #%d"),notetime); throw MAXException(ProgressMsg.data()); } if( time.isNull() ) { ProgressMsg.printf(_T("Missing notify time in notekey #%d"),notetime); throw MAXException(ProgressMsg.data()); } buf.printf( _T("#exec MESH NOTIFY MESH=%s SEQ=%s TIME=%s FUNCTION=%s"), FileName, SeqName, time, func ); _fputts( buf, fScript ); } } } } // TODO: write materials if( Materials.Count() > 0 ) { for( int i=0; i<Materials.Count(); ++i ) { IGameMaterial* mat = Materials[i].Mat; if( mat == NULL ) continue; _ftprintf( fScript, _T("#exec MESHMAP SETTEXTURE MESHMAP=%s NUM=%d TEXTURE=%s \n"), FileName, i, _T("DefaultTexture") ); } } } }
int Unreal3DExport::DoExport( const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options ) { int Result = FALSE; // Set a global prompt display switch bShowPrompts = suppressPrompts ? false : true; bExportSelected = (options & SCENE_EXPORT_SELECTED) ? true : false; // Get file names SplitFilename(TSTR(name), &FilePath, &FileName, &FileExt); if( MatchPattern(FileName,TSTR(_T("*_d")),TRUE) || MatchPattern(FileName,TSTR(_T("*_a")),TRUE) ) { FileName = FileName.Substr(0,FileName.length()-2); } ModelFileName = FilePath + _T("\\") + FileName + TSTR(_T("_d")) + FileExt; AnimFileName = FilePath + _T("\\") + FileName + TSTR(_T("_a")) + FileExt; ScriptFileName = FilePath + _T("\\") + FileName + TSTR(_T("_rc.uc")); // Open Log fLog = _tfopen(FilePath + _T("\\") + FileName + _T(".log") ,_T("wb")); // Init pInt = GetCOREInterface(); pInt->ProgressStart( GetString(IDS_INFO_INIT), TRUE, fn, this); Progress += U3D_PROGRESS_INIT; try { MyErrorProc pErrorProc; SetErrorCallBack(&pErrorProc); ReadConfig(); //if(bShowPrompts) /*DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), Unreal3DExportOptionsDlgProc, (LPARAM)this);*/ //if(showPrompts) { // Prompt the user with our dialogbox, and get all the options. if(!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), Unreal3DExportOptionsDlgProc, (LPARAM)this)) { throw CancelException(); } } // Enumerate interesting nodes Init(); // Fetch data from nodes GetTris(); GetAnim(); // Prepare data for writing Prepare(); // Write to files WriteScript(); WriteModel(); WriteTracking(); // Show optional summary ShowSummary(); WriteConfig(); Result = IMPEXP_SUCCESS; } catch( CancelException& ) { Result = IMPEXP_CANCEL; } catch( MAXException& e ) { if( bShowPrompts && !e.message.isNull() ) { MaxMsgBox(pInt->GetMAXHWnd(),e.message,ShortDesc(),MB_OK|MB_ICONERROR); } Result = IMPEXP_FAIL; } // Release scene if( pScene != NULL ) { pScene->ReleaseIGame(); pScene = NULL; } // Close files fclosen(fMesh); fclosen(fAnim); fclosen(fLog); fclosen(fScript); // Return to MAX pInt->ProgressEnd(); return Result; }
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; }