/** * @brief * Returns the position, rotation and scale of the scene node at a given time */ void PLSceneNode::GetPosRotScale(Point3 &vPos, Quat &qRot, Point3 &vScale, TimeValue nTime) { if (m_pIGameNode) { // Get the position, rotation and scale - relative to the parent node GMatrix mParentMatrix; IGameNode *pIGameNodeParent = m_pIGameNode->GetNodeParent(); if (pIGameNodeParent) mParentMatrix = pIGameNodeParent->GetWorldTM(nTime); PLTools::GetPosRotScale(m_pIGameNode->GetWorldTM(nTime)*PLTools::Inverse(mParentMatrix), vPos, qRot, vScale, IsRotationFlipped()); // Get the scale (NOT done for special nodes!) if (m_nType != TypeContainer && m_nType != TypeScene && m_nType != TypeCell && m_nType != TypeCamera && m_nType != TypeLight) { // [TODO] Do we still need this hint? // Check for none uniform scale // if (m_vScale.x != m_vScale.y || m_vScale.x != m_vScale.z || m_vScale.y != m_vScale.z) { // We have to use '%e' because else we may get output like '(1 1 1) is no uniform scale' // g_pLog->LogFLine(PLLog::Hint, "Node '%s' has a none uniform scale. (%e %e %e) This 'may' cause problems in special situations...", m_sName.c_str(), m_vScale.x, m_vScale.y, m_vScale.z); // } } else { // Set scale to 1 vScale.Set(1.0f, 1.0f, 1.0f); } } }
void CModelExporter::Export(const char* pszFileName) { m_serializer.Reset(); size_t uTotalRootNodeCnt = m_pIGameScene->GetTopLevelNodeCount(); std::vector<IGameNode*> meshNodeVector; for(size_t x = 0; x < uTotalRootNodeCnt; x++) { IGameNode* pNode = m_pIGameScene->GetTopLevelNode(x); IGameObject* pObject = pNode->GetIGameObject(); IGameObject::ObjectTypes gameType = pObject->GetIGameType(); if(gameType == IGameObject::IGAME_MESH) { meshNodeVector.push_back(pNode); } } int uMeshNodeCount = meshNodeVector.size(); m_serializer << uMeshNodeCount; for(auto pNode : meshNodeVector) { ExportMesh(pNode); } m_serializer.Deserialize(pszFileName); }
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 ); } } }
ExporterF3D::EExportError ExporterF3D::CreateModel() { m_scene = new CSceneData(); s32 nodeCount = m_iGameScene->GetTopLevelNodeCount(); LOG_INFO("In Game Scene found [%d] Nodes", nodeCount); if (nodeCount == 0) { return eSceneEmptyError; } s32 id = 0; m_scene->setId(id); m_scene->setName(""); LOG_INFO("Game Scene Name %s, id %d", TCHARToString(m_iGameScene->GetSceneFileName()).c_str(), id); for (u32 objectIndex = 0; objectIndex < nodeCount; ++objectIndex) { IGameNode* gameNode = m_iGameScene->GetTopLevelNode(objectIndex); LOG_INFO("Processing Parent object [%d/%d:%s] ", objectIndex + 1, nodeCount, TCHARToString(gameNode->GetName()).c_str()); EExportError error = ExportNode(gameNode, objectIndex); if (error != eNoError) { return error; } } return eNoError; }
void MeshExporter::ExtractSkeleton(IGameNode * node) { if(!node->IsGroupOwner()) _dumpJoint(node); for(int i=0;i<node->GetChildCount();i++) { IGameNode * child = node->GetNodeChild(i); // we deal with targets in the light/camera section if(child->IsTarget()) continue; ExtractSkeleton(child); } node->ReleaseIGameObject(); }
int TrianExporter::DoExport( const TCHAR * name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options ) { //Open the file to export to. m_of.open( name ); //Create an Error procedure. MyErrorProc pErrorProc; SetErrorCallBack( &pErrorProc ); //Get the game interface m_pIGame = GetIGameInterface(); //Start the progress bar. i->ProgressStart( _T( "Exporting to .trian file..." ), TRUE, fn, NULL ); //Set up the conversion manager. IGameConversionManager * cm = GetConversionManager(); //Set up the whacky coordinate system that 3DS Max uses. UserCoord whacky = { 1, //Right-Handed. 1, //X Axis goes right. 4, //Y Axis goes in. 3, //Z Axis goes down. 0, //U Tex Axis is left. 1 //V Tex Axis is down. }; cm->SetUserCoordSystem( whacky ); //Set the coordinate system. cm->SetCoordSystem( IGameConversionManager::IGAME_MAX ); //Initialize the game scene. m_pIGame->InitialiseIGame( options & SCENE_EXPORT_SELECTED ); //Go through all the nodes of the scene and export only the Game Meshes. for( int l = 0; l < m_pIGame->GetTopLevelNodeCount(); l++ ) { //Get the current Game node. IGameNode * node = m_pIGame->GetTopLevelNode( l ); //Check for selected state. if( node->IsTarget() ) continue; ExportNodeInfo( node ); } //End the progress bar. i->ProgressEnd(); //Release the scene. m_pIGame->ReleaseIGame(); m_pIGame = 0; //Close the output stream. m_of.close(); return TRUE; }
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; } }
/** * @brief * Adds a 3ds Max node to the scene */ bool PLSceneContainer::AddIGameNode(IGameNode &cIGameNode) { // Unknown node type by default EType nType = TypeUnknown; // Is there a '.' within the node name? If yes, replace it by '-'. String sName = cIGameNode.GetName(); int nIndex = sName.IndexOf("."); if (nIndex >= 0) { g_pLog->LogFLine(PLLog::Warning, "Node name '%s' has '.' within it, '.' is replaced by '-' automatically", cIGameNode.GetName()); char *pszName = const_cast<char*>(sName.GetASCII()) + nIndex; while (*pszName != '\0') { if (*pszName == '.') *pszName = '-'; pszName++; } } const char *pszName = sName.GetASCII(); // Look for 'cell_' (cell_<cell name>_<node name> or cell_<cell name>_<mesh name>_<instance name>) String sSceneCellName, sTargetSceneCellName, sSceneNodeName, sMeshName; if (!_strnicmp(pszName, "cell_", 5)) { // Get the name of the cell const char *pszNameT = pszName += 5; // Check for '\0' if (*pszNameT == '\0') { g_pLog->LogFLine(PLLog::Error, "Node name '%s' does not follow the name convention cell_<cell name>_<node name> or cell_<cell name>_<mesh name>_<instance name>. <cell name> is missing!", cIGameNode.GetName()); sSceneCellName = "?"; sMeshName = "?"; sSceneNodeName = "?"; } else { // Read the cell name while (*pszNameT != '_' && *pszNameT != '\0') pszNameT++; sSceneCellName.Insert(pszName, 0, pszNameT-pszName); // Check for '_' if (*pszNameT != '_') { g_pLog->LogFLine(PLLog::Error, "Node name '%s' does not follow the name convention cell_<cell name>_<node name> or cell_<cell name>_<mesh name>_<instance name>. <mesh name>/<instance name> is missing!", cIGameNode.GetName()); sMeshName = "?"; sSceneNodeName = "?"; } else { // Skip '_' pszNameT++; // Get the name of the node/mesh pszName = pszNameT; while (*pszNameT != '_' && *pszNameT != '\0') pszNameT++; sMeshName.Insert(pszName, 0, pszNameT-pszName); // Check for '_' if (*pszNameT != '_') { // Check for spaces within the mesh name CheckAndCorrectName(sMeshName, cIGameNode.GetName(), "mesh"); // cell_<cell name>_<node name> is used so node name = mesh name sSceneNodeName = sMeshName; // Construct a 'save' mesh name later if the final scene node name is known... sMeshName = ""; } else { // Skip '_' pszNameT++; // Get the name of the scene node sSceneNodeName = sMeshName+"_"; pszName = pszNameT; while (*pszNameT != '_' && *pszNameT != '\0') pszNameT++; sSceneNodeName.Insert(pszName, sSceneNodeName.GetLength(), pszNameT-pszName); // Is there an instance name? - No log hint because people find this behavior annoying... // if (!(pszNameT-pszName)) // g_pLog->LogFLine(PLLog::Hint, "Node name '%s' does not follow the name convention cell_<cell name>_<mesh name>_<instance name>. <instance name> is missing!", cIGameNode.GetName()); // Check for spaces and tabs within the mesh and node names CheckAndCorrectName(sMeshName, cIGameNode.GetName(), "mesh"); CheckAndCorrectName(sSceneNodeName, cIGameNode.GetName(), "node"); } } } // Check for spaces/tabs within the cell name CheckAndCorrectName(sSceneCellName, cIGameNode.GetName(), "cell"); // Look for 'portal_' (portal_<from cell>_<to cell>) } else if (!_strnicmp(pszName, "portal_", 7)) { // Get the name of the cell, the cell-portal is a scene node of this cell :) const char *pszNameT = pszName += 7; // Check for '\0' if (*pszNameT == '\0') { g_pLog->LogFLine(PLLog::Error, "Node name '%s' does not follow the name convention portal_<from cell>_<to cell>. <from cell> is missing!", cIGameNode.GetName()); sSceneCellName = "?"; sTargetSceneCellName = "?"; } else { // Read the cell name while (*pszNameT != '_' && *pszNameT != '\0') pszNameT++; sSceneCellName.Insert(pszName, 0, pszNameT-pszName); // Check for '_' if (*pszNameT != '_') { g_pLog->LogFLine(PLLog::Error, "Node name '%s' does not follow the name convention portal_<from cell>_<to cell>. <to cell> is missing!", cIGameNode.GetName()); sTargetSceneCellName = "?"; } else { // Skip '_' pszNameT++; // Get the name of the target cell pszName = pszNameT; while (*pszNameT != '_' && *pszNameT != '\0') pszNameT++; sTargetSceneCellName.Insert(pszName, 0, pszNameT-pszName); } } // Check for spaces/tabs within the names CheckAndCorrectName(sSceneCellName, cIGameNode.GetName(), "cell"); CheckAndCorrectName(sTargetSceneCellName, cIGameNode.GetName(), "target cell"); // Get the name of the scene node sSceneNodeName = "CellPortalTo_"; sSceneNodeName += sTargetSceneCellName; // Get the 'real' target cell name - in our case, this cell MUST be within the parent container... sTargetSceneCellName = "Parent." + sTargetSceneCellName; // Set the correct scene node type nType = TypeCellPortal; // Look for 'antiportal_' (antiportal_<name>) } else if (!_strnicmp(pszName, "antiportal_", 11)) { // Get the name of the anti-portal) sSceneNodeName = String("AntiPortal_") + (pszName += 11); // Set the correct scene node type nType = TypeAntiPortal; // ... } else { // No log hint because people find this behavior annoying... // g_pLog->LogFLine(PLLog::Hint, "Node name '%s' does not follow the name convention cell_<cell name>_<node name> or cell_<cell name>_<mesh name>_<instance name>. Node is added to the scene root.", cIGameNode.GetName()); // Set scene node name sSceneNodeName = pszName; } // Check whether the scene cell and node names are valid if (sSceneCellName.CompareNoCase("This")) { sSceneCellName += '-'; g_pLog->LogFLine(PLLog::Warning, "'This' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneCellName.GetASCII()); } if (sSceneCellName.CompareNoCase("Root")) { sSceneCellName += '-'; g_pLog->LogFLine(PLLog::Warning, "'Root' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneCellName.GetASCII()); } if (sSceneCellName.CompareNoCase("Parent")) { sSceneCellName += '-'; g_pLog->LogFLine(PLLog::Warning, "'Parent' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneCellName.GetASCII()); } if (sSceneNodeName.CompareNoCase("This")) { sSceneNodeName += '-'; g_pLog->LogFLine(PLLog::Warning, "'This' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneNodeName.GetASCII()); } if (sSceneNodeName.CompareNoCase("Root")) { sSceneNodeName += '-'; g_pLog->LogFLine(PLLog::Warning, "'Root' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneNodeName.GetASCII()); } if (sSceneNodeName.CompareNoCase("Parent")) { sSceneNodeName += '-'; g_pLog->LogFLine(PLLog::Warning, "'Root' is NOT allowed as node name. (3ds Max node '%s') Name is changed into '%s' ", cIGameNode.GetName(), sSceneNodeName.GetASCII()); } // Get cell, this scene node is in PLSceneCell *pCell = GetCell(sSceneCellName, cIGameNode); // The exporter isn't case sensitive, but compare the 'real' cell names just for sure :) if (pCell && pCell->GetName() != sSceneCellName) g_pLog->LogFLine(PLLog::Warning, "Node '%s' is within the cell '%s', but '%s' was written -> It's recommended to take care of lower/upper case!", cIGameNode.GetName(), pCell->GetName().GetASCII(), sSceneCellName.GetASCII()); // Get the container the new scene node is created in. If no cell was found, create the scene node // within THIS container. PLSceneContainer *pContainer = pCell ? pCell : this; // Check whether there's already an scene node with this name, if so, rename it and write a warning // into the log String sSceneNodeNameLower = sSceneNodeName; sSceneNodeNameLower.ToLower(); // Do ONLY use lower case, else the hashing will NOT return the same values! std::map<String, PLSceneNode*>::iterator pIterator = pContainer->m_mapNodes.find(sSceneNodeNameLower); if (pIterator != pContainer->m_mapNodes.end()) { String sNewName; int nConflictIndex = 1; // Find an unused scene node name do { sNewName = sSceneNodeName; sNewName += "_Conflict_"; sNewName += PLTools::ToString(nConflictIndex); nConflictIndex++; sSceneNodeNameLower = sNewName; sSceneNodeNameLower.ToLower(); // Do ONLY use lower case, else the hashing will NOT return the same values! pIterator = pContainer->m_mapNodes.find(sSceneNodeNameLower); } while (pIterator != pContainer->m_mapNodes.end()); // Write a log message g_pLog->LogFLine(PLLog::Warning, "'%s': There's already a scene node with the name '%s' within the container '%s' -> Changed name into '%s'", cIGameNode.GetName(), sSceneNodeName.GetASCII(), sSceneCellName.GetASCII(), sNewName.GetASCII()); // Set the new name sSceneNodeName = sNewName; } // Construct a 'save' mesh name... if (!sMeshName.GetLength()) sMeshName = sSceneCellName.GetLength() ? sSceneCellName + '_' + sSceneNodeName : sSceneNodeName; // Are there any children? If yes, we need to create a container for this node containing THIS node AND the children... if (cIGameNode.GetChildCount()) { PLSceneContainer *pNewContainer = new PLSceneContainer(pContainer, sSceneNodeName); // Register the new scene node pContainer->m_lstSceneNodes.push_back(pNewContainer); sSceneNodeNameLower = sSceneNodeName; sSceneNodeNameLower.ToLower(); // Do ONLY use lower case, else the hashing will NOT return the same values! pContainer->m_mapNodes.insert(std::make_pair(sSceneNodeNameLower, pNewContainer)); // The new container becomes the current container pContainer = pNewContainer; // [TODO] Update the statistics // pContainer->m_sStatistics.nNumOfUnknown++; // GetScene().m_sSceneStatistics.nNumOfUnknown++; } // Create the scene node... PLSceneNode *pSceneNode = nullptr; INode *pMaxNode = cIGameNode.GetMaxNode(); if (pMaxNode) { Object *pMaxObject = pMaxNode->GetObjectRef(); if (pMaxObject) { // Get 'real' 3ds Max object (we really need to do this) while (pMaxObject->SuperClassID() == GEN_DERIVOB_CLASS_ID) pMaxObject = static_cast<IDerivedObject*>(pMaxObject)->GetObjRef(); // Check the type of the object switch (pMaxObject->SuperClassID()) { case LIGHT_CLASS_ID: // Create the scene node pSceneNode = new PLSceneLight(*pContainer, cIGameNode, sSceneNodeName); // Update the statistics pContainer->m_sStatistics.nNumOfLights++; GetScene().m_sSceneStatistics.nNumOfLights++; break; case GEOMOBJECT_CLASS_ID: // Is this a cell-portal? if (nType == TypeCellPortal) { // Create the scene node pSceneNode = new PLSceneCellPortal(*pContainer, cIGameNode, sSceneNodeName, sTargetSceneCellName); // Update the number of outgoing cell-portals if (pContainer->GetType() == TypeCell) { static_cast<PLSceneCell*>(pContainer)->m_lstOutgoingCellPortals.push_back(static_cast<PLSceneCellPortal*>(pSceneNode)); // ?? There's something totally wrong! ?? } else { g_pLog->LogFLine(PLLog::Warning, "'%s': This cell-portal is within the container '%s', but cell-portals should only be within cells!", cIGameNode.GetName(), sTargetSceneCellName.GetASCII()); } // Update the statistics pContainer->m_sStatistics.nNumOfCellPortals++; GetScene().m_sSceneStatistics.nNumOfCellPortals++; // Is this a anti-portal? } else if (nType == TypeAntiPortal) { // Create the scene node pSceneNode = new PLSceneAntiPortal(*pContainer, cIGameNode, sSceneNodeName); // Update the statistics pContainer->m_sStatistics.nNumOfAntiPortals++; GetScene().m_sSceneStatistics.nNumOfAntiPortals++; } else { // [TODO] Add rename to mesh node... // Create the scene node pSceneNode = new PLSceneObject(*pContainer, cIGameNode, sSceneNodeName, GetScene().AddMesh(cIGameNode, sMeshName)); // Update the statistics pContainer->m_sStatistics.nNumOfObjects++; GetScene().m_sSceneStatistics.nNumOfObjects++; } break; case SHAPE_CLASS_ID: // Create the scene node pSceneNode = new PLSceneSpline(*pContainer, cIGameNode, sSceneNodeName); // We do not need to update the statistics... break; case CAMERA_CLASS_ID: // Create the scene node pSceneNode = new PLSceneCamera(*pContainer, cIGameNode, sSceneNodeName); // Update the statistics pContainer->m_sStatistics.nNumOfCameras++; GetScene().m_sSceneStatistics.nNumOfCameras++; break; case HELPER_CLASS_ID: // Create the scene node pSceneNode = new PLSceneHelper(*pContainer, cIGameNode, sSceneNodeName); // Update the statistics pContainer->m_sStatistics.nNumOfHelpers++; GetScene().m_sSceneStatistics.nNumOfHelpers++; break; default: // Create the scene node pSceneNode = new PLSceneUnknown(*pContainer, cIGameNode, sSceneNodeName); // Update the statistics pContainer->m_sStatistics.nNumOfUnknown++; GetScene().m_sSceneStatistics.nNumOfUnknown++; break; } } } // Valid scene node? if (pSceneNode) { // Are there any children? If yes, we need to create a container for this node containing THIS node AND the children... if (cIGameNode.GetChildCount()) { // Setup the scene container pContainer->m_bFixedCenter = true; pContainer->m_vCenter.Set(0.0f, 0.0f, 0.0f); pContainer->m_vPos = pSceneNode->m_vPos; pContainer->m_vRot = pSceneNode->m_vRot; // Setup the scene node 'creating' the scene container pSceneNode->m_vPos.Set(0.0f, 0.0f, 0.0f); pSceneNode->m_vRot.Set(0.0f, 0.0f, 0.0f); } // Register the new scene node pContainer->m_lstSceneNodes.push_back(pSceneNode); sSceneNodeNameLower = sSceneNodeName; sSceneNodeNameLower.ToLower(); // Do ONLY use lower case, else the hashing will NOT return the same values! pContainer->m_mapNodes.insert(std::make_pair(sSceneNodeNameLower, pSceneNode)); { // Add to 3ds Max node to PL node map String sKey = String::Format("%19p", cIGameNode.GetMaxNode()); GetScene().m_mapMaxToPLNodes.insert(std::make_pair(sKey, pSceneNode)); } // Loop through all child nodes for (int nNode=0; nNode<cIGameNode.GetChildCount(); nNode++) { IGameNode *pIGameNode = cIGameNode.GetNodeChild(nNode); if (pIGameNode) { g_pLog->LogFLine(PLLog::Scene, "Found 3ds Max child node: %s", pIGameNode->GetName()); pContainer->AddIGameNode(*pIGameNode); } } // Done return true; } // Error! return false; }
void Unreal3DExport::GetTris() { // Export triangle data FJSMeshTri nulltri = FJSMeshTri(); for( int n=0; n<Nodes.Count(); ++n ) { CheckCancel(); IGameNode* node = Nodes[n]; IGameMesh* mesh = static_cast<IGameMesh*>(node->GetIGameObject()); if( mesh->InitializeData() ) { int vertcount = mesh->GetNumberOfVerts(); int tricount = mesh->GetNumberOfFaces(); if( vertcount > 0 && tricount > 0 ) { // Progress ProgressMsg.printf(GetString(IDS_INFO_MESH),n+1,Nodes.Count(),TSTR(node->GetName())); pInt->ProgressUpdate(Progress+(static_cast<float>(n)/Nodes.Count()*U3D_PROGRESS_MESH), FALSE, ProgressMsg.data()); // Alloc triangles space Tris.Resize(Tris.Count()+tricount); // Append triangles for( int i=0; i!=tricount; ++i ) { FaceEx* f = mesh->GetFace(i); if( f ) { FJSMeshTri tri(nulltri); // TODO: add material id listing RegisterMaterial( node, mesh, f, &tri ); tri.iVertex[0] = VertsPerFrame + f->vert[0]; tri.iVertex[1] = VertsPerFrame + f->vert[1]; tri.iVertex[2] = VertsPerFrame + f->vert[2]; Point2 p; if( mesh->GetTexVertex(f->texCoord[0],p) ){ tri.Tex[0] = FMeshUV(p); } if( mesh->GetTexVertex(f->texCoord[1],p) ){ tri.Tex[1] = FMeshUV(p); } if( mesh->GetTexVertex(f->texCoord[2],p) ){ tri.Tex[2] = FMeshUV(p); } Tris.Append(1,&tri); } } VertsPerFrame += vertcount; } else { // remove invalid node Nodes.Delete(n--,1); } } node->ReleaseIGameObject(); } Progress += U3D_PROGRESS_MESH; }
void MeshExporter::ExtractMesh(IGameNode * node) { IGameObject* obj = node->GetIGameObject(); // export option bool expColor = ExportConfig::Instance()->IsExportColor(); bool expNormal = ExportConfig::Instance()->IsExportNormal(); bool expTexcoord = ExportConfig::Instance()->IsExportTexcoord(); bool expLightmapUV = ExportConfig::Instance()->IsExportLightmapUV(); obj->InitializeData(); const char * nodeName = node->GetName(); IGameNode * parent = node->GetNodeParent(); IGameMesh::ObjectTypes type = obj->GetIGameType(); if (type == IGameMesh::IGAME_MESH) { IGameMesh* mesh = (IGameMesh*) obj; Tab<int> texMaps = mesh->GetActiveMapChannelNum(); mMeshData.VertexElems |= MeshSerializer::VE_POSITION; // position for (int i = 0; i < mesh->GetNumberOfVerts(); ++i) mMeshData.P.PushBack(Utility::ToFloat3(mesh->GetVertex(i))); // vertex color for (int i = 0; expColor && i < mesh->GetNumberOfColorVerts(); ++i) { Point3 c = mesh->GetColorVertex(i); float a = mesh->GetAlphaVertex(i); mMeshData.C.PushBack(Float4(c.x, c.y, c.z, a)); mMeshData.VertexElems |= MeshSerializer::VE_COLOR; } // normal for (int i = 0; expNormal && i < mesh->GetNumberOfNormals(); ++i) { mMeshData.N.PushBack(Utility::ToFloat3(mesh->GetNormal(i))); mMeshData.VertexElems |= MeshSerializer::VE_NORMAL; } // uv for (int i = 0; expTexcoord && texMaps.Count() > 1 && i < mesh->GetNumberOfMapVerts(texMaps[1]); ++i) { Point3 tv = mesh->GetMapVertex(texMaps[1], i); mMeshData.UV.PushBack(Float2(tv.x, 1 - tv.y)); mMeshData.VertexElems |= MeshSerializer::VE_TEXCOORD; } // light map uv for (int i = 0; expLightmapUV && texMaps.Count() > 2 && i < mesh->GetNumberOfMapVerts(texMaps[2]); ++i) { Point3 tv = mesh->GetMapVertex(texMaps[2], i); mMeshData.LUV.PushBack(Float2(tv.x, 1 - tv.y)); mMeshData.VertexElems |= MeshSerializer::VE_LIGHTMAPUV; } IGameSkin * skin = obj->GetIGameSkin(); if (skin != NULL) _dumpSkinInfo(skin); else if (parent != NULL && parent->GetIGameObject()->GetIGameType() == IGameMesh::IGAME_BONE) _genSkinInfo(parent); _dumpMeshBuffer(mesh); mMeshData.Clear(); } for(int i=0;i<node->GetChildCount();i++) { IGameNode * child = node->GetNodeChild(i); // we deal with targets in the light/camera section if(child->IsTarget()) continue; ExtractMesh(child); } node->ReleaseIGameObject(); }
void MeshExporter::Export() { mRoot = new Root; mResourceManager = new ResourceManager; mRenderSystem = new NullRenderSystem; mWorld = new World; try { IGameConversionManager* cm = GetConversionManager(); cm->SetCoordSystem(IGameConversionManager::IGAME_D3D); mGameScene->InitialiseIGame(ExportConfig::Instance()->IsExportSelected()); mGameScene->SetStaticFrame(0); int nodeCount = mGameScene->GetTopLevelNodeCount(); if (nodeCount == 0) { MessageBox(GetActiveWindow(), "No nodes available!", "Error", MB_OK); goto __end; } mMeshSource = MeshManager::Instance()->NewMesh("MaxExporter"); // extract skeleton for (int i = 0; i < nodeCount; ++i) { IGameNode* node = mGameScene->GetTopLevelNode(i); if (node->IsNodeHidden()) continue ; ExtractSkeleton(node); } // extract mesh mMeshData.Clear(); for (int i = 0; i < nodeCount; ++i) { IGameNode* node = mGameScene->GetTopLevelNode(i); if (node->IsNodeHidden()) continue ; ExtractMesh(node); } if (mMMPairs.Size() == 0) { MessageBox(GetActiveWindow(), "No Objects!", "Error", MB_OK); goto __end; } BuildMesh(); // save mesh MeshSerializer::Save(mMeshSource.c_ptr(), ExportConfig::Instance()->GetExportFilename()); MessageBox(GetActiveWindow(), "Export OK!", "Info", MB_ICONINFORMATION); } catch (...) { MessageBox(GetActiveWindow(), "Error!", "Error", MB_ICONEXCLAMATION); } __end: mMeshSource = NULL; delete mWorld; delete mRenderSystem; delete mResourceManager; delete mRoot; }
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; }