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 MaterialExporter::streamMaterial(std::ostream &of) {

		// serialize this information to the material file
		MaterialMap::iterator it = m_materialMap.begin();

		while (it != m_materialMap.end()) {
			std::string matName(it->first);
			IGameMaterial *mtl = it->second;

			of << "material " << matName << std::endl;
			of << std::showpoint;
			of << "{" << std::endl;

			of << "\ttechnique" << std::endl;
			of << "\t{" << std::endl;

			int numSubMtl = 0;
			
			if (mtl != NULL) {
				numSubMtl = mtl->GetSubMaterialCount();

				if (numSubMtl > 0) {
					int i;
					for (i=0; i<numSubMtl; i++) {
						streamPass(of, mtl->GetSubMaterial(i));
					}
				}
				else
					streamPass(of, mtl);
			}
			else {
				streamPass(of, mtl);
			}

			of << "\t}" << std::endl;
			of << "}" << std::endl;

			it++;
		}

		m_materialMap.clear();

		return true;
	}
void Unreal3DExport::RegisterMaterial( IGameNode* node, IGameMesh* mesh, FaceEx* f, FJSMeshTri* tri )
{
    tri->TextureNum = f->matID;

    int matid = f->matID;

    IGameMaterial* mat = mesh->GetMaterialFromFace(f);
    if( mat )
    {
        Tab<TSTR*> tokens = TokStr(mat->GetMaterialName(),_T(" \t,;"));
        for( int i=0; i!=tokens.Count(); ++i )
        {
            if( MatchPattern(*tokens[i],TSTR(_T("F=*")),TRUE) )
            {
                SplitStr(*tokens[i],_T('='));
                tri->Flags = static_cast<byte>(_ttoi(tokens[i]->data()));
            }
        }
        tokens.Delete(0,tokens.Count());

        if( Materials.Count() <= matid )
        {
            Materials.Append(matid-Materials.Count()+1,&sMaterial::DefaultMaterial);
        }
        
        if( Materials[matid].Mat != mat )
        {
            Materials[matid].Mat = mat;
        }

        /*for( int i=0; i!=mat->GetSubMaterialCount(); ++i )
        {
            IGameMaterial* sub = mat->GetSubMaterial(i);
            if( sub )
            {
                TSTR matname = sub->GetMaterialName();
                int subid = mat->GetMaterialID(i);
                int x = 0;
            }
        }*/
    }
}
void CModelExporter::ExportMesh( IGameNode* pNode )
{
    IGameMesh* pMesh = (IGameMesh*)pNode->GetIGameObject();

    pMesh->SetUseWeightedNormals();
    pMesh->InitializeData();
    pMesh->InitializeBinormalData();

    IGameMaterial* pRootMat = pNode->GetNodeMaterial();
    if(pRootMat != NULL)
    {
        size_t uMatCnt = 0;
        GetMaterialCnt(pRootMat, uMatCnt);

        m_serializer << uMatCnt;
        for(size_t x = 0; x < uMatCnt; x++)
        {
            size_t index = x;
            int nChildID;
            IGameMaterial* pParentMat;
            IGameMaterial* pMat = GetMaterial(index, pRootMat, NULL, -1, &pParentMat, &nChildID);

            int nMatID = 0;
            if(pParentMat != NULL)
            {
                nMatID = pParentMat->GetMaterialID(nChildID);
                BEATS_ASSERT(pParentMat->GetSubMaterial(nChildID) == pMat);
            }

            if(pMat != NULL)
            {
                ExportMeshMaterial(pNode, pMesh, pMat, nMatID, pRootMat->IsMultiType());
                ExportMeshVertex(pNode, pMesh,pMat,nMatID,pRootMat->IsMultiType());
            }
        }
    }

}
	bool MeshXMLExporter::Export(OutputMap& output) 
	{

		try {

			// write XML to a strstream
			std::stringstream of;

			while (!m_submeshNames.empty())
				m_submeshNames.pop();

			if (m_pGame) {
				m_pGame->ReleaseIGame();
				m_pGame = 0;
			}

			m_ei->theScene->EnumTree(this);

			m_pGame = GetIGameInterface();
			IGameConversionManager* cm = GetConversionManager();
			cm->SetCoordSystem(IGameConversionManager::IGAME_OGL);
			m_pGame->InitialiseIGame(m_nodeTab, false);
			m_pGame->SetStaticFrame(0);
			int nodeCount = m_pGame->GetTopLevelNodeCount();

			if (nodeCount == 0) {
				MessageBox(GetActiveWindow(), "No nodes available to export, aborting...", "Nothing To Export", MB_ICONINFORMATION);
				m_pGame->ReleaseIGame();
				return false;
			}

			// if we are writing everything to one file, use the name provided when the user first started the export;
			// otherwise, create filenames on the basis of the node (submesh) names
			std::string fileName;
			IGameNode* node = m_pGame->GetTopLevelNode(0);
			if (!m_config.getExportMultipleFiles())
				fileName = m_config.getExportFilename();
			else {
				fileName = m_config.getExportPath() + "\\";
				fileName += node->GetName();
				fileName += ".mesh.xml";
			}

			// write start of XML data
			streamFileHeader(of);

			int nodeIdx = 0;
			std::map<std::string, std::string> materialScripts;

			while (nodeIdx < nodeCount) {

				std::string mtlName;
				IGameNode* node = m_pGame->GetTopLevelNode(nodeIdx);
				IGameObject* obj = node->GetIGameObject();

				// InitializeData() is important -- it performs all of the WSM/time eval for us; no data without it
				obj->InitializeData();
				
				IGameMaterial* mtl = node->GetNodeMaterial();
				if (mtl == NULL)
					mtlName = m_config.getDefaultMaterialName();
				else
					mtlName = mtl->GetMaterialName();

				// clean out any spaces the user left in their material name
				std::string::size_type pos;
				while ((pos = mtlName.find_first_of(' ')) != std::string::npos)
					mtlName.replace(pos, 1, _T("_"));

				if (materialScripts.find(mtlName) == materialScripts.end()) {

					// export new material script
					MaterialExporter mexp(m_config, m_materialMap);
					std::string script;

					mexp.buildMaterial(mtl, mtlName, script);
					materialScripts[mtlName] = script;
				}

				//if (streamSubmesh(of, node, mtlName))
				if (streamSubmesh(of, obj, mtlName))
					m_submeshNames.push(std::string(node->GetName()));

				node->ReleaseIGameObject();
				nodeIdx++;

				if (m_config.getExportMultipleFiles() || nodeIdx == nodeCount) {

					// write end of this file's XML
					streamFileFooter(of);

					// insert new filename --> stream pair into output map
					output[fileName] = std::string(of.str());
					of.str("");

					if (nodeIdx != nodeCount) {
						fileName = m_config.getExportPath() + "\\";
						node = m_pGame->GetTopLevelNode(nodeIdx);
						fileName += node->GetName();
						fileName += ".mesh.xml";

						// start over again with new data
						streamFileHeader(of);
					}
				}
			}

			m_pGame->ReleaseIGame();

			// export materials if we are writing those
			if (m_config.getExportMaterial()) {

				std::ofstream materialFile;
				materialFile.open((m_config.getExportPath() + "\\" + m_config.getMaterialFilename()).c_str(), std::ios::out);

				if (materialFile.is_open()) {
					for (std::map<std::string, std::string>::iterator it = materialScripts.begin();
						it != materialScripts.end(); ++it)
					{
						materialFile << it->second;
					}

					materialFile.close();
				}
			}

			return true;
		}
		catch (...) {
			MessageBox(GetActiveWindow(), "An unexpected error has occurred while trying to export, aborting", "Error", MB_ICONEXCLAMATION);

			if (m_pGame)
				m_pGame->ReleaseIGame();

			return false;
		}
	}
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;
}