void CModelConverter::SaveSIA(const tstring& sFilename) { tstring sSIAFileName = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sFilename).c_str() + _T(".sia"); std::wofstream sFile(convertstring<tchar, char>(sSIAFileName).c_str()); if (!sFile.is_open()) return; sFile.precision(8); sFile.setf(std::ios::fixed, std::ios::floatfield); if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction(_T("Writing materials..."), 0); } sFile << _T("-Version 1.0") << std::endl; for (size_t i = 0; i < m_pScene->GetNumMaterials(); i++) { sFile << _T("-Mat") << std::endl; CConversionMaterial* pMaterial = m_pScene->GetMaterial(i); sFile << "-amb " << pMaterial->m_vecAmbient.x << _T(" ") << pMaterial->m_vecAmbient.y << _T(" ") << pMaterial->m_vecAmbient.z << _T(" 0") << std::endl; sFile << "-dif " << pMaterial->m_vecDiffuse.x << _T(" ") << pMaterial->m_vecDiffuse.y << _T(" ") << pMaterial->m_vecDiffuse.z << _T(" 0") << std::endl; sFile << "-spec " << pMaterial->m_vecSpecular.x << _T(" ") << pMaterial->m_vecSpecular.y << _T(" ") << pMaterial->m_vecSpecular.z << _T(" 0") << std::endl; sFile << "-emis " << pMaterial->m_vecEmissive.x << _T(" ") << pMaterial->m_vecEmissive.y << _T(" ") << pMaterial->m_vecEmissive.z << _T(" 0") << std::endl; sFile << "-shin " << pMaterial->m_flShininess << std::endl; sFile << "-name \"" << pMaterial->GetName().c_str() << _T("\"") << std::endl; if (pMaterial->GetDiffuseTexture().length() > 0) sFile << "-tex \"" << pMaterial->GetDiffuseTexture().c_str() << _T("\"") << std::endl; sFile << _T("-endMat") << std::endl; } for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { CConversionMesh* pMesh = m_pScene->GetMesh(i); size_t iAddV = pMesh->GetNumVertices(); size_t iAddE = pMesh->GetNumEdges(); size_t iAddUV = pMesh->GetNumUVs(); size_t iAddN = pMesh->GetNumNormals(); // Find the default scene for this mesh. CConversionSceneNode* pScene = NULL; for (size_t j = 0; j < m_pScene->GetNumScenes(); j++) { if (m_pScene->GetScene(j)->GetName() == pMesh->GetName() + _T(".sia")) { pScene = m_pScene->GetScene(j); break; } } tstring sNodeName = pMesh->GetName(); sFile << _T("-Shape") << std::endl; sFile << _T("-snam \"") << sNodeName.c_str() << _T("\"") << std::endl; sFile << _T("-shad 0") << std::endl; sFile << _T("-shadw 1") << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" vertices...")).c_str(), pMesh->GetNumVertices()); for (size_t iVertices = 0; iVertices < pMesh->GetNumVertices(); iVertices++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iVertices); Vector vecVertex = pMesh->GetVertex(iVertices); sFile << _T("-vert ") << vecVertex.x << _T(" ") << vecVertex.y << _T(" ") << vecVertex.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" edges...")).c_str(), pMesh->GetNumEdges()); tstring sCreases; for (size_t iEdges = 0; iEdges < pMesh->GetNumEdges(); iEdges++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iEdges); CConversionEdge* pEdge = pMesh->GetEdge(iEdges); sFile << _T("-edge ") << pEdge->v1 << _T(" ") << pEdge->v2 << std::endl; if (pEdge->m_bCreased) sCreases += sprintf(tstring(" %d"), iEdges); } if (sCreases.length()) sFile << _T("-creas") << sCreases.c_str() << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" faces...")).c_str(), pMesh->GetNumFaces()); size_t iMaterial = 0; for (size_t iFaces = 0; iFaces < pMesh->GetNumFaces(); iFaces++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iFaces); CConversionFace* pFace = pMesh->GetFace(iFaces); if (iFaces == 0 || iMaterial != pFace->m) { iMaterial = pFace->m; if (iMaterial == ~0) sFile << _T("-setmat -1") << std::endl; else { CConversionSceneNode* pNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh, false); if (!pNode || pNode->GetNumMeshInstances() != 1) sFile << _T("-setmat -1") << std::endl; else { CConversionMaterialMap* pMap = pNode->GetMeshInstance(0)->GetMappedMaterial(iMaterial); if (pMap) sFile << _T("-setmat -1") << std::endl; else sFile << _T("-setmat ") << pMap->m_iMaterial << std::endl; } } } sFile << _T("-face ") << pFace->GetNumVertices(); TAssert(pFace->GetNumEdges() == pFace->GetNumVertices()); for (size_t iVertsInFace = 0; iVertsInFace < pFace->GetNumVertices(); iVertsInFace++) { CConversionVertex* pVertex = pFace->GetVertex(iVertsInFace); CConversionVertex* pNextVertex = pFace->GetVertex((iVertsInFace+1)%pFace->GetNumVertices()); // Find the edge that heads in a counter-clockwise direction. size_t iEdge = ~0; for (size_t i = 0; i < pFace->GetNumEdges(); i++) { size_t iEdgeCandidate = pFace->GetEdge(i); CConversionEdge* pEdge = pMesh->GetEdge(iEdgeCandidate); if ((pEdge->v1 == pVertex->v && pEdge->v2 == pNextVertex->v) || (pEdge->v2 == pVertex->v && pEdge->v1 == pNextVertex->v)) { iEdge = iEdgeCandidate; break; } } TAssert(iEdge != ~0); Vector vecUV = pMesh->GetUV(pVertex->vu); sFile << _T(" ") << pVertex->v << _T(" ") << iEdge << _T(" ") << vecUV.x << _T(" ") << vecUV.y; } sFile << std::endl; } sFile << _T("-axis 0 0.5 0 1 0 0 0 1 0 0 0 1") << std::endl; sFile << _T("-mirp 0 0 0 1 0 0") << std::endl; sFile << _T("-endShape") << std::endl; } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
const tchar* CModelConverter::ReadSIAShape(const tchar* pszLine, const tchar* pszEnd, CConversionSceneNode* pScene, bool bCare) { size_t iCurrentMaterial = ~0; CConversionMesh* pMesh = NULL; CConversionSceneNode* pMeshNode = NULL; size_t iAddV = 0; size_t iAddE = 0; size_t iAddUV = 0; size_t iAddN = 0; tstring sLastTask; tstring sToken; const tchar* pszNextLine = NULL; while (pszLine < pszEnd) { if (pszNextLine) pszLine = pszNextLine; size_t iLineLength = tstrlen(pszLine); pszNextLine = pszLine + iLineLength + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; const tchar* pszToken = pszLine; while (*pszToken && *pszToken != _T(' ')) pszToken++; sToken.reserve(iLineLength); sToken.clear(); sToken.append(pszLine, pszToken-pszLine); sToken[pszToken-pszLine] = _T('\0'); pszToken = sToken.c_str(); if (!bCare) { if (tstrncmp(pszToken, _T("-endShape"), 9) == 0) return pszNextLine; else continue; } if (tstrncmp(pszToken, _T("-snam"), 5) == 0) { // We name our mesh. tstring sName =pszLine+6; eastl::vector<tstring> aName; tstrtok(sName, aName, _T("\"")); // Strip out the quotation marks. if (bCare) { size_t iMesh = m_pScene->FindMesh(aName[0].c_str()); if (iMesh == (size_t)~0) { iMesh = m_pScene->AddMesh(aName[0].c_str()); pMesh = m_pScene->GetMesh(iMesh); pMesh->AddBone(aName[0].c_str()); } else { pMesh = m_pScene->GetMesh(iMesh); iAddV = pMesh->GetNumVertices(); iAddE = pMesh->GetNumEdges(); iAddUV = pMesh->GetNumUVs(); iAddN = pMesh->GetNumNormals(); } // Make sure it exists. pMeshNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh); } } else if (tstrncmp(pszToken, _T("-vert"), 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction(_T("Reading vertex data"), 0); sLastTask = tstring(pszToken); } } // A vertex. float v[3]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+5; int iDimension = 0; while (*pszToken) { while (pszToken[0] == _T(' ')) pszToken++; v[iDimension++] = (float)stof(pszToken); if (iDimension >= 3) break; while (pszToken[0] != _T(' ')) pszToken++; } pMesh->AddVertex(v[0], v[1], v[2]); } else if (tstrncmp(pszToken, _T("-edge"), 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction(_T("Reading edge data"), 0); sLastTask = tstring(pszToken); } } // An edge. We only need them so we can tell where the creases are, so we can calculate normals properly. int e[2]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+5; int iDimension = 0; while (*pszToken) { while (pszToken[0] == _T(' ')) pszToken++; e[iDimension++] = (int)stoi(pszToken); if (iDimension >= 2) break; while (pszToken[0] != _T(' ')) pszToken++; } pMesh->AddEdge(e[0]+iAddV, e[1]+iAddV); } else if (tstrncmp(pszToken, _T("-creas"), 6) == 0) { // An edge. We only need them so we can tell where the creases are, so we can calculate normals properly. tstring sCreases = pszLine+7; eastl::vector<tstring> aCreases; tstrtok(sCreases, aCreases, _T(" ")); size_t iCreases = aCreases.size(); // The first one is the number of creases, skip it for (size_t i = 1; i < iCreases; i++) { int iEdge = stoi(aCreases[i].c_str()); pMesh->GetEdge(iEdge+iAddE)->m_bCreased = true; } } else if (tstrncmp(pszToken, _T("-setmat"), 7) == 0) { const tchar* pszMaterial = pszLine+8; size_t iNewMaterial = stoi(pszMaterial); if (iNewMaterial == (size_t)(-1)) iCurrentMaterial = ~0; else { CConversionMaterial* pMaterial = m_pScene->GetMaterial(iNewMaterial); if (pMaterial) { iCurrentMaterial = pMesh->FindMaterialStub(pMaterial->GetName()); if (iCurrentMaterial == (size_t)~0) { size_t iMaterialStub = pMesh->AddMaterialStub(pMaterial->GetName()); m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh)->GetMeshInstance(0)->AddMappedMaterial(iMaterialStub, iNewMaterial); iCurrentMaterial = iMaterialStub; } } else iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, pMesh->GetName()); } } else if (tstrncmp(pszToken, _T("-face"), 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction(_T("Reading polygon data"), 0); sLastTask = tstring(pszToken); } } // A face. size_t iFace = pMesh->AddFace(iCurrentMaterial); if (iFace == 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+6; size_t iVerts = stoi(pszToken); while (pszToken[0] != _T(' ')) pszToken++; size_t iProcessed = 0; while (iProcessed++ < iVerts) { size_t iVertex = stoi(++pszToken)+iAddV; while (pszToken[0] != _T(' ')) pszToken++; size_t iEdge = stoi(++pszToken)+iAddE; while (pszToken[0] != _T(' ')) pszToken++; float flU = (float)stof(++pszToken); while (pszToken[0] != _T(' ')) pszToken++; float flV = (float)stof(++pszToken); size_t iUV = pMesh->AddUV(flU, flV); size_t iNormal = pMesh->AddNormal(0, 0, 1); // For now! pMesh->AddVertexToFace(iFace, iVertex, iUV, iNormal); pMesh->AddEdgeToFace(iFace, iEdge); while (pszToken[0] != _T('\0') && pszToken[0] != _T(' ')) pszToken++; } } else if (tstrncmp(pszToken, _T("-axis"), 5) == 0) { // This is the manipulator position and angles. The code below is untested and probably has the elements in the wrong // order. We don't support writing yet so no need to load it so I'm not bothering with it now. /* Matrix4x4& m = pMeshNode->m_mManipulator; swscanf(sLine.c_str(), _T("-axis %f %f %f %f %f %f %f %f %f"), &m.m[0][3], &m.m[1][3], &m.m[2][3], &m.m[0][0], &m.m[0][1], &m.m[0][2], // ? &m.m[1][0], &m.m[1][1], &m.m[1][2], // ? &m.m[2][0], &m.m[2][1], &m.m[2][2] // ? );*/ } else if (tstrncmp(pszToken, _T("-endShape"), 9) == 0) { break; } } return pszNextLine; }
const tchar* CModelConverter::ReadSIAShape(const tchar* pszLine, const tchar* pszEnd, CConversionSceneNode* pScene, bool bCare) { size_t iCurrentMaterial = ~0; CConversionMesh* pMesh = NULL; CConversionSceneNode* pMeshNode = NULL; size_t iAddV = 0; size_t iAddE = 0; size_t iAddUV = 0; size_t iAddN = 0; tstring sLastTask; tstring sToken; const tchar* pszNextLine = NULL; while (pszLine < pszEnd) { if (pszNextLine) pszLine = pszNextLine; size_t iLineLength = tstrlen(pszLine); pszNextLine = pszLine + iLineLength + 1; // This code used to call StripWhitespace() but that's too slow for very large files w/ millions of lines. // Instead we'll just cut the whitespace off the front and deal with whitespace on the end when we come to it. while (*pszLine && IsWhitespace(*pszLine)) pszLine++; if (tstrlen(pszLine) == 0) continue; const tchar* pszToken = pszLine; while (*pszToken && *pszToken != ' ') pszToken++; sToken.reserve(iLineLength); sToken.clear(); sToken.append(pszLine, pszToken-pszLine); pszToken = sToken.c_str(); if (!bCare) { if (tstrncmp(pszToken, "-endShape", 9) == 0) return pszNextLine; else continue; } if (tstrncmp(pszToken, "-snam", 5) == 0) { // We name our mesh. tstring sName =pszLine+6; tvector<tstring> aName; tstrtok(sName, aName, "\""); // Strip out the quotation marks. if (bCare) { size_t iMesh = m_pScene->FindMesh(aName[0].c_str()); if (iMesh == (size_t)~0) { iMesh = m_pScene->AddMesh(aName[0].c_str()); pMesh = m_pScene->GetMesh(iMesh); pMesh->AddBone(aName[0].c_str()); } else { pMesh = m_pScene->GetMesh(iMesh); iAddV = pMesh->GetNumVertices(); iAddE = pMesh->GetNumEdges(); iAddUV = pMesh->GetNumUVs(); iAddN = pMesh->GetNumNormals(); } // Make sure it exists. pMeshNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh); } } else if (tstrncmp(pszToken, "-vert", 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction("Reading vertex data", 0); sLastTask = tstring(pszToken); } } // A vertex. float v[3]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+5; int iDimension = 0; while (*pszToken) { while (pszToken[0] == ' ') pszToken++; v[iDimension++] = (float)stof(pszToken); if (iDimension >= 3) break; while (pszToken[0] != ' ') pszToken++; } pMesh->AddVertex(v[0], v[1], v[2]); } else if (tstrncmp(pszToken, "-edge", 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction("Reading edge data", 0); sLastTask = tstring(pszToken); } } // An edge. We only need them so we can tell where the creases are, so we can calculate normals properly. int e[2]; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+5; int iDimension = 0; while (*pszToken) { while (pszToken[0] == ' ') pszToken++; e[iDimension++] = (int)stoi(pszToken); if (iDimension >= 2) break; while (pszToken[0] != ' ') pszToken++; } pMesh->AddEdge(e[0]+iAddV, e[1]+iAddV); } else if (tstrncmp(pszToken, "-creas", 6) == 0) { // An edge. We only need them so we can tell where the creases are, so we can calculate normals properly. tstring sCreases = pszLine+7; tvector<tstring> aCreases; tstrtok(sCreases, aCreases, " "); size_t iCreases = aCreases.size(); // The first one is the number of creases, skip it for (size_t i = 1; i < iCreases; i++) { int iEdge = stoi(aCreases[i].c_str()); pMesh->GetEdge(iEdge+iAddE)->m_bCreased = true; } } else if (tstrncmp(pszToken, "-setmat", 7) == 0) { const tchar* pszMaterial = pszLine+8; size_t iNewMaterial = stoi(pszMaterial); if (iNewMaterial == (size_t)(-1)) iCurrentMaterial = ~0; else { CConversionMaterial* pMaterial = m_pScene->GetMaterial(iNewMaterial); if (pMaterial) { iCurrentMaterial = pMesh->FindMaterialStub(pMaterial->GetName()); if (iCurrentMaterial == (size_t)~0) { size_t iMaterialStub = pMesh->AddMaterialStub(pMaterial->GetName()); m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh)->GetMeshInstance(0)->AddMappedMaterial(iMaterialStub, iNewMaterial); iCurrentMaterial = iMaterialStub; } } else iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, pMesh->GetName()); } } else if (tstrncmp(pszToken, "-face", 5) == 0) { if (m_pWorkListener) { if (sLastTask == pszToken) m_pWorkListener->WorkProgress(0); else { m_pWorkListener->SetAction("Reading polygon data", 0); sLastTask = tstring(pszToken); } } // A face. size_t iFace = pMesh->AddFace(iCurrentMaterial); // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszToken = pszLine+6; size_t iVerts = stoi(pszToken); while (pszToken[0] != ' ') pszToken++; size_t iProcessed = 0; while (iProcessed++ < iVerts) { size_t iVertex = stoi(++pszToken)+iAddV; while (pszToken[0] != ' ') pszToken++; size_t iEdge = stoi(++pszToken)+iAddE; while (pszToken[0] != ' ') pszToken++; float flU = (float)stof(++pszToken); while (pszToken[0] != ' ') pszToken++; float flV = (float)stof(++pszToken); size_t iUV = pMesh->AddUV(flU, flV); size_t iNormal = pMesh->AddNormal(0, 0, 1); // For now! pMesh->AddVertexToFace(iFace, iVertex, iUV, iNormal); pMesh->AddEdgeToFace(iFace, iEdge); while (pszToken[0] != '\0' && pszToken[0] != ' ') pszToken++; } } else if (tstrncmp(pszToken, "-axis", 5) == 0) { // Object's transformations. Format is translation x y z, forward base vector x y z, then up vector and right vector. // Y is up. Matrix4x4 m; sscanf(pszLine, "-axis %f %f %f %f %f %f %f %f %f %f %f %f", &m.m[3][0], &m.m[3][1], &m.m[3][2], &m.m[0][0], &m.m[0][1], &m.m[0][2], &m.m[1][0], &m.m[1][1], &m.m[1][2], &m.m[2][0], &m.m[2][1], &m.m[2][2]); Matrix4x4 mGlobalToLocal = m.InvertedRT(); // Unfortunately Silo stores all vertex data in global coordinates so we need to move them to the local frame first. size_t iVerts = pMesh->GetNumVertices(); for (size_t i = 0; i < iVerts; i++) pMesh->m_aVertices[i] = mGlobalToLocal * pMesh->m_aVertices[i]; pMeshNode->m_mTransformations = m; } else if (tstrncmp(pszToken, "-endShape", 9) == 0) { break; } } return pszNextLine; }
void CModelConverter::SaveOBJ(const tstring& sFilename) { tstring sMaterialFileName = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sFilename).c_str() + _T(".mtl"); std::wofstream sMaterialFile(convertstring<tchar, char>(sMaterialFileName).c_str()); if (!sMaterialFile.is_open()) return; if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction(_T("Writing materials file"), 0); } for (size_t i = 0; i < m_pScene->GetNumMaterials(); i++) { CConversionMaterial* pMaterial = m_pScene->GetMaterial(i); sMaterialFile << "newmtl " << pMaterial->GetName().c_str() << std::endl; sMaterialFile << "Ka " << pMaterial->m_vecAmbient.x << _T(" ") << pMaterial->m_vecAmbient.y << _T(" ") << pMaterial->m_vecAmbient.z << std::endl; sMaterialFile << "Kd " << pMaterial->m_vecDiffuse.x << _T(" ") << pMaterial->m_vecDiffuse.y << _T(" ") << pMaterial->m_vecDiffuse.z << std::endl; sMaterialFile << "Ks " << pMaterial->m_vecSpecular.x << _T(" ") << pMaterial->m_vecSpecular.y << _T(" ") << pMaterial->m_vecSpecular.z << std::endl; sMaterialFile << "d " << pMaterial->m_flTransparency << std::endl; sMaterialFile << "Ns " << pMaterial->m_flShininess << std::endl; sMaterialFile << "illum " << pMaterial->m_eIllumType << std::endl; if (pMaterial->GetDiffuseTexture().length() > 0) sMaterialFile << "map_Kd " << pMaterial->GetDiffuseTexture().c_str() << std::endl; sMaterialFile << std::endl; } sMaterialFile.close(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { CConversionMesh* pMesh = m_pScene->GetMesh(i); // Find the default scene for this mesh. CConversionSceneNode* pScene = NULL; for (size_t j = 0; j < m_pScene->GetNumScenes(); j++) { if (m_pScene->GetScene(j)->GetName() == pMesh->GetName() + _T(".obj")) { pScene = m_pScene->GetScene(j); break; } } tstring sNodeName = pMesh->GetName(); tstring sOBJFilename = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sNodeName).c_str() + _T(".obj"); tstring sMTLFilename = tstring(GetFilename(sFilename).c_str()) + _T(".mtl"); if (m_pScene->GetNumMeshes() == 1) sOBJFilename = sFilename; std::wofstream sOBJFile(convertstring<tchar, char>(sOBJFilename).c_str()); sOBJFile.precision(8); sOBJFile.setf(std::ios::fixed, std::ios::floatfield); sOBJFile << _T("mtllib ") << sMTLFilename.c_str() << std::endl; sOBJFile << std::endl; sOBJFile << _T("o ") << sNodeName.c_str() << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" vertices...")).c_str(), pMesh->GetNumVertices()); for (size_t iVertices = 0; iVertices < pMesh->GetNumVertices(); iVertices++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iVertices); Vector vecVertex = pMesh->GetVertex(iVertices); sOBJFile << _T("v ") << vecVertex.x << _T(" ") << vecVertex.y << _T(" ") << vecVertex.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" normals...")).c_str(), pMesh->GetNumNormals()); for (size_t iNormals = 0; iNormals < pMesh->GetNumNormals(); iNormals++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iNormals); Vector vecNormal = pMesh->GetNormal(iNormals); sOBJFile << _T("vn ") << vecNormal.x << _T(" ") << vecNormal.y << _T(" ") << vecNormal.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" UVs...")).c_str(), pMesh->GetNumUVs()); for (size_t iUVs = 0; iUVs < pMesh->GetNumUVs(); iUVs++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iUVs); Vector vecUV = pMesh->GetUV(iUVs); sOBJFile << _T("vt ") << vecUV.x << _T(" ") << vecUV.y << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" faces...")).c_str(), pMesh->GetNumFaces()); size_t iLastMaterial = ~0; for (size_t iFaces = 0; iFaces < pMesh->GetNumFaces(); iFaces++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iFaces); CConversionFace* pFace = pMesh->GetFace(iFaces); if (pFace->m != iLastMaterial) { iLastMaterial = pFace->m; CConversionSceneNode* pNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh, false); if (!pNode || pNode->GetNumMeshInstances() != 1) sOBJFile << "usemtl " << iLastMaterial << std::endl; else { CConversionMaterialMap* pMap = pNode->GetMeshInstance(0)->GetMappedMaterial(iLastMaterial); if (!pMap) sOBJFile << "usemtl " << iLastMaterial << std::endl; else sOBJFile << "usemtl " << m_pScene->GetMaterial(pMap->m_iMaterial)->GetName().c_str() << std::endl; } } sOBJFile << _T("f"); for (size_t iVertsInFace = 0; iVertsInFace < pFace->GetNumVertices(); iVertsInFace++) { CConversionVertex* pVertex = pFace->GetVertex(iVertsInFace); sOBJFile << _T(" ") << pVertex->v+1 << _T("/") << pVertex->vu+1 << _T("/") << pVertex->vn+1; } sOBJFile << std::endl; } sOBJFile << std::endl; sOBJFile.close(); } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::SaveDAE(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FCollada::Initialize(); FCDocument* pDoc = FCollada::NewTopDocument(); FCDocumentTools::StandardizeUpAxisAndLength(pDoc, FMVector3(0, 1, 0)); FCDAsset* pAsset = pDoc->GetAsset(); FCDAssetContributor* pContributor = pAsset->AddContributor(); pContributor->SetAuthoringTool(fstring_literal("Created by SMAK using FCollada")); FCDMaterialLibrary* pMatLib = pDoc->GetMaterialLibrary(); if (m_pWorkListener) m_pWorkListener->SetAction("Saving materials", m_pScene->GetNumMaterials()); for (size_t iMaterial = 0; iMaterial < m_pScene->GetNumMaterials(); iMaterial++) { CConversionMaterial* pConversionMaterial = m_pScene->GetMaterial(iMaterial); FCDMaterial* pColladaMaterial = pMatLib->AddEntity(); pColladaMaterial->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffect* pEffect = pMatLib->GetDocument()->GetEffectLibrary()->AddEntity(); pColladaMaterial->SetEffect(pEffect); FCDEffectProfile* pEffectProfile = pEffect->AddProfile(FUDaeProfileType::COMMON); pEffect->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffectStandard* pStandardProfile = dynamic_cast<FCDEffectStandard*>(pEffectProfile); if (pStandardProfile) { pStandardProfile->SetLightingType(FCDEffectStandard::PHONG); pStandardProfile->SetAmbientColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecAmbient), 1)); pStandardProfile->SetDiffuseColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecDiffuse), 1)); pStandardProfile->SetSpecularColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecSpecular), 1)); pStandardProfile->SetEmissionColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecEmissive), 1)); pStandardProfile->SetShininess(pConversionMaterial->m_flShininess); } if (pConversionMaterial->GetDiffuseTexture().length()) { FCDEffectParameter* pEffectParameterSampler = pEffectProfile->AddEffectParameter(FCDEffectParameter::SAMPLER); FCDEffectParameter* pEffectParameterSurface = pEffectProfile->AddEffectParameter(FCDEffectParameter::SURFACE); FCDEffectParameterSampler* pSampler = dynamic_cast<FCDEffectParameterSampler*>(pEffectParameterSampler); FCDEffectParameterSurface* pSurface = dynamic_cast<FCDEffectParameterSurface*>(pEffectParameterSurface); FCDImage* pSurfaceImage = pMatLib->GetDocument()->GetImageLibrary()->AddEntity(); pSurfaceImage->SetFilename(convert_to_fstring(pConversionMaterial->GetDiffuseTexture())); pSurface->SetInitMethod(new FCDEffectParameterSurfaceInitFrom()); pSurface->AddImage(pSurfaceImage); pSurface->SetReference((pConversionMaterial->GetName() + "-surface").c_str()); pSampler->SetSurface(pSurface); } if (m_pWorkListener) m_pWorkListener->WorkProgress(iMaterial); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving geometry", m_pScene->GetNumMeshes()); FCDGeometryLibrary* pGeoLib = pDoc->GetGeometryLibrary(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); ++i) { CConversionMesh* pConversionMesh = m_pScene->GetMesh(i); FCDGeometry* pGeometry = pGeoLib->AddEntity(); pGeometry->SetName(convert_to_fstring(pConversionMesh->GetName())); pGeometry->CreateMesh(); FCDGeometryMesh* pMesh = pGeometry->GetMesh(); FCDGeometrySource* pPositionSource = pMesh->AddSource(FUDaeGeometryInput::POSITION); pPositionSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-position")); pPositionSource->SetStride(3); pPositionSource->SetValueCount(pConversionMesh->GetNumVertices()); for (size_t j = 0; j < pConversionMesh->GetNumVertices(); j++) pPositionSource->SetValue(j, pConversionMesh->GetVertex(j)); pMesh->AddVertexSource(pPositionSource); FCDGeometrySource* pNormalSource = pMesh->AddSource(FUDaeGeometryInput::NORMAL); pNormalSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-normal")); pNormalSource->SetStride(3); pNormalSource->SetValueCount(pConversionMesh->GetNumNormals()); for (size_t j = 0; j < pConversionMesh->GetNumNormals(); j++) pNormalSource->SetValue(j, pConversionMesh->GetNormal(j)); FCDGeometrySource* pUVSource = NULL; if (pConversionMesh->GetNumUVs()) { pUVSource = pMesh->AddSource(FUDaeGeometryInput::TEXCOORD); pUVSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-texcoord")); pUVSource->SetStride(2); pUVSource->SetValueCount(pConversionMesh->GetNumUVs()); for (size_t j = 0; j < pConversionMesh->GetNumUVs(); j++) pUVSource->SetValue(j, pConversionMesh->GetUV(j)); } for (size_t iMaterials = 0; iMaterials < pConversionMesh->GetNumMaterialStubs(); iMaterials++) { CConversionMaterialStub* pStub = pConversionMesh->GetMaterialStub(iMaterials); FCDGeometryPolygons* pPolygons = pMesh->AddPolygons(); pPolygons->SetMaterialSemantic(convert_to_fstring(pStub->GetName())); pPolygons->AddInput(pPositionSource, 0); pPolygons->AddInput(pNormalSource, 1); if (pConversionMesh->GetNumUVs()) pPolygons->AddInput(pUVSource, 2); FCDGeometryPolygonsInput* pPositionInput = pPolygons->FindInput(pPositionSource); FCDGeometryPolygonsInput* pNormalInput = pPolygons->FindInput(pNormalSource); FCDGeometryPolygonsInput* pUVInput = pPolygons->FindInput(pUVSource); for (size_t iFace = 0; iFace < pConversionMesh->GetNumFaces(); iFace++) { CConversionFace* pFace = pConversionMesh->GetFace(iFace); if (pFace->m != iMaterials) continue; pPolygons->AddFaceVertexCount(pFace->GetNumVertices()); for (size_t iVertex = 0; iVertex < pFace->GetNumVertices(); iVertex++) { pPositionInput->AddIndex(pFace->GetVertex(iVertex)->v); pNormalInput->AddIndex(pFace->GetVertex(iVertex)->vn); if (pConversionMesh->GetNumUVs()) pUVInput->AddIndex(pFace->GetVertex(iVertex)->vu); } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving scenes", m_pScene->GetNumScenes()); FCDVisualSceneNodeLibrary* pVisualScenes = pDoc->GetVisualSceneLibrary(); for (size_t i = 0; i < m_pScene->GetNumScenes(); ++i) { FCDSceneNode* pNode = pVisualScenes->AddEntity(); SaveDAEScene(pNode, m_pScene->GetScene(i)); if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Writing to disk...", 0); FCollada::SaveDocument(pDoc, convert_to_fstring(sFilename)); pDoc->Release(); FCollada::Release(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }