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