void CEditorPanel::ChooseInputCallback(const tstring& sArgs) { m_hInput->Pop(true, true); auto pOutput = GetCurrentOutput(); if (!pOutput) return; tvector<tstring> asTokens; tstrtok(sArgs, asTokens); pOutput->m_sInput = asTokens[1]; m_hInput->SetText(pOutput->m_sInput); }
void CCommand::Run(tstring sCommand) { tvector<tstring> asTokens; tstrtok(sCommand, asTokens); if (asTokens.size() == 0) return; tmap<tstring, CCommand*>::iterator it = GetCommands().find(asTokens[0]); if (it == GetCommands().end()) { TMsg("Unrecognized command.\n"); return; } CCommand* pCommand = it->second; pCommand->m_pfnCallback(pCommand, asTokens, sCommand); }
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::ReadSIAMat(const tchar* pszLine, const tchar* pszEnd, CConversionSceneNode* pScene, const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading materials"), 0); size_t iCurrentMaterial = m_pScene->AddMaterial(_T("")); CConversionMaterial* pMaterial = m_pScene->GetMaterial(iCurrentMaterial); const tchar* pszNextLine = NULL; while (pszLine < pszEnd) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 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; eastl::vector<tstring> aTokens; tstrtok(pszLine, aTokens, _T(" ")); const tchar* pszToken = aTokens[0].c_str(); if (tstrncmp(pszToken, _T("-name"), 5) == 0) { tstring sName = pszLine+6; eastl::vector<tstring> aName; tstrtok(sName, aName, _T("\"")); // Strip out the quotation marks. pMaterial->m_sName = aName[0]; } else if (tstrncmp(pszToken, _T("-dif"), 4) == 0) { eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecDiffuse.x = stof(asTokens[1]); pMaterial->m_vecDiffuse.y = stof(asTokens[2]); pMaterial->m_vecDiffuse.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("-amb"), 4) == 0) { eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecAmbient.x = stof(asTokens[1]); pMaterial->m_vecAmbient.y = stof(asTokens[2]); pMaterial->m_vecAmbient.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("-spec"), 5) == 0) { eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecSpecular.x = stof(asTokens[1]); pMaterial->m_vecSpecular.y = stof(asTokens[2]); pMaterial->m_vecSpecular.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("-emis"), 5) == 0) { eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecEmissive.x = stof(asTokens[1]); pMaterial->m_vecEmissive.y = stof(asTokens[2]); pMaterial->m_vecEmissive.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("-shin"), 5) == 0) { eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 2) pMaterial->m_flShininess = stof(asTokens[1]); } else if (tstrncmp(pszToken, _T("-tex"), 4) == 0) { const tchar* pszTexture = pszLine+5; tstring sName = pszTexture; eastl::vector<tstring> aName; tstrtok(sName, aName, _T("\"")); // Strip out the quotation marks. tstring sDirectory = GetDirectory(sFilename); pMaterial->m_sDiffuseTexture = sprintf(tstring("%s/%s"), sDirectory.c_str(), aName[0].c_str()); } else if (tstrncmp(pszToken, _T("-endMat"), 7) == 0) { return pszNextLine; } } return pszNextLine; }
// Silo ascii void CModelConverter::ReadSIA(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".sia")))); if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); if (pszCurrent[iLength-1] == _T('\n')) { pszCurrent[iLength-1] = _T('\0'); iLength--; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 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; eastl::vector<tstring> aTokens; tstrtok(pszLine, aTokens, _T(" ")); const tchar* pszToken = aTokens[0].c_str(); if (tstrncmp(pszToken, _T("-Version"), 8) == 0) { // Warning if version is later than 1.0, we may not support it int iMajor, iMinor; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" .")); if (asTokens.size() >= 3) { iMajor = stoi(asTokens[1]); iMinor = stoi(asTokens[2]); if (iMajor != 1 && iMinor != 0) printf("WARNING: I was programmed for version 1.0, this file is version %d.%d, so this might not work exactly right!\n", iMajor, iMinor); } } else if (tstrncmp(pszToken, _T("-Mat"), 4) == 0) { pszNextLine = ReadSIAMat(pszNextLine, pszCurrent, pScene, sFilename); } else if (tstrncmp(pszToken, _T("-Shape"), 6) == 0) { pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene); } else if (tstrncmp(pszToken, _T("-Texshape"), 9) == 0) { // This is the 3d UV space of the object, but we only care about its 2d UV space which is contained in rhw -Shape section, so meh. pszNextLine = ReadSIAShape(pszNextLine, pszCurrent, pScene, false); } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } m_pScene->CalculateExtends(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::ReadOBJ(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FILE* fp = tfopen(sFilename, _T("r")); if (!fp) { printf("No input file. Sorry!\n"); return; } CConversionSceneNode* pScene = m_pScene->GetScene(m_pScene->AddScene(GetFilename(sFilename).append(_T(".obj")))); CConversionMesh* pMesh = m_pScene->GetMesh(m_pScene->AddMesh(GetFilename(sFilename))); // Make sure it exists. CConversionSceneNode* pMeshNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh); size_t iCurrentMaterial = ~0; size_t iSmoothingGroup = ~0; bool bSmoothingGroups = false; tstring sLastTask; int iTotalVertices = 0; int iTotalFaces = 0; int iVerticesComplete = 0; int iFacesComplete = 0; if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading file into memory..."), 0); fseek(fp, 0L, SEEK_END); long iOBJSize = ftell(fp); fseek(fp, 0L, SEEK_SET); // Make sure we allocate more than we need just in case. size_t iFileSize = (iOBJSize+1) * (sizeof(tchar)+1); tchar* pszEntireFile = (tchar*)malloc(iFileSize); tchar* pszCurrent = pszEntireFile; pszCurrent[0] = _T('\0'); // Read the entire file into an array first for faster processing. tstring sLine; while (fgetts(sLine, fp)) { tstrncpy(pszCurrent, iFileSize-(pszCurrent-pszEntireFile), sLine.c_str(), sLine.length()); size_t iLength = sLine.length(); tchar cLastChar = pszCurrent[iLength-1]; while (cLastChar == _T('\n') || cLastChar == _T('\r')) { pszCurrent[iLength-1] = _T('\0'); iLength--; cLastChar = pszCurrent[iLength-1]; } pszCurrent += iLength; pszCurrent++; if (m_pWorkListener) m_pWorkListener->WorkProgress(0); } pszCurrent[0] = _T('\0'); fclose(fp); const tchar* pszLine = pszEntireFile; const tchar* pszNextLine = NULL; while (pszLine < pszCurrent) { if (pszNextLine) pszLine = pszNextLine; pszNextLine = pszLine + tstrlen(pszLine) + 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; if (pszLine[0] == '#') { // ZBrush is kind enough to notate exactly how many vertices and faces we have in the comments at the top of the file. if (tstrncmp(pszLine, _T("#Vertex Count"), 13) == 0) { iTotalVertices = stoi(pszLine+13); pMesh->SetTotalVertices(iTotalVertices); } if (tstrncmp(pszLine, _T("#Face Count"), 11) == 0) { iTotalFaces = stoi(pszLine+11); pMesh->SetTotalFaces(iTotalFaces); // Don't kill the video card while we're loading the faces. if (iTotalFaces > 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); } continue; } tchar szToken[1024]; tstrncpy(szToken, 1024, pszLine, 1024); tchar* pszState = NULL; tchar* pszToken = strtok<tchar>(szToken, " ", &pszState); if (tstrncmp(pszToken, _T("mtllib"), 6) == 0) { tstring sDirectory = GetDirectory(sFilename); tstring sMaterial = sprintf(tstring("%s/%s"), sDirectory.c_str(), pszLine + 7); ReadMTL(sMaterial); } else if (tstrncmp(pszToken, _T("o"), 1) == 0) { // Dunno what this does. } else if (tstrncmp(pszToken, _T("v"), 2) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iVerticesComplete++); else { m_pWorkListener->SetAction(_T("Reading vertex data"), iTotalVertices); 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+1; 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("vn"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading vertex normal data"), 0); } sLastTask = tstring(pszToken); // A vertex normal. float x, y, z; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 4) { x = stof(asTokens[1]); y = stof(asTokens[2]); z = stof(asTokens[3]); pMesh->AddNormal(x, y, z); } } else if (tstrncmp(pszToken, _T("vt"), 3) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(0); else m_pWorkListener->SetAction(_T("Reading texture coordinate data"), 0); } sLastTask = tstring(pszToken); // A UV coordinate for a vertex. float u, v; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 3) { u = stof(asTokens[1]); v = stof(asTokens[2]); pMesh->AddUV(u, v); } } else if (tstrncmp(pszToken, _T("g"), 1) == 0) { // A group of faces. pMesh->AddBone(pszLine+2); } else if (tstrncmp(pszToken, _T("usemtl"), 6) == 0) { // All following faces should use this material. tstring sMaterial = tstring(pszLine+7); size_t iMaterial = pMesh->FindMaterialStub(sMaterial); if (iMaterial == ((size_t)~0)) { size_t iSceneMaterial = m_pScene->FindMaterial(sMaterial); if (iSceneMaterial == ((size_t)~0)) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, sMaterial); else { size_t iMaterialStub = pMesh->AddMaterialStub(sMaterial); m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh)->GetMeshInstance(0)->AddMappedMaterial(iMaterialStub, iSceneMaterial); iCurrentMaterial = iMaterialStub; } } else iCurrentMaterial = iMaterial; } else if (tstrncmp(pszToken, _T("s"), 1) == 0) { if (tstrncmp(pszLine, _T("s off"), 5) == 0) { iSmoothingGroup = ~0; } else { bSmoothingGroups = true; eastl::vector<tstring> asTokens; tstrtok(pszLine, asTokens, _T(" ")); if (asTokens.size() == 2) iSmoothingGroup = stoi(asTokens[1]); } } else if (tstrncmp(pszToken, _T("f"), 1) == 0) { if (m_pWorkListener) { if (tstrncmp(sLastTask.c_str(), pszToken, sLastTask.length()) == 0) m_pWorkListener->WorkProgress(iFacesComplete++); else { m_pWorkListener->SetAction(_T("Reading polygon data"), iTotalFaces); sLastTask = tstring(pszToken); } } if (iCurrentMaterial == ~0) iCurrentMaterial = m_pScene->AddDefaultSceneMaterial(pScene, pMesh, pMesh->GetName()); // A face. size_t iFace = pMesh->AddFace(iCurrentMaterial); // If we get to 10k faces force the mesh off so it doesn't kill the video card. if (iFace == 10000) pMeshNode->GetMeshInstance(0)->SetVisible(false); pMesh->GetFace(iFace)->m_iSmoothingGroup = iSmoothingGroup; while (pszToken = strtok<tchar>(NULL, _T(" "), &pszState)) { if (tstrlen(pszToken) == 0) continue; // We don't use size_t because SOME EXPORTS put out negative numbers. long f[3]; bool bValues[3]; bValues[0] = false; bValues[1] = false; bValues[2] = false; // scanf is pretty slow even for such a short string due to lots of mallocs. const tchar* pszValues = pszToken; int iValue = 0; do { if (!pszValues) break; if (!bValues[0] || pszValues[0] == _T('/')) { if (pszValues[0] == _T('/')) pszValues++; bValues[iValue] = true; f[iValue++] = (long)stoi(pszValues); if (iValue >= 3) break; } // Don't advance if we're on a slash, because that means empty slashes. ie, 11//12 <-- the 12 would get skipped. if (pszValues[0] != _T('/')) pszValues++; } while (*pszValues); if (bValues[0]) { if (f[0] < 0) f[0] = (long)pMesh->GetNumVertices()+f[0]+1; TAssert ( f[0] >= 1 && f[0] < (long)pMesh->GetNumVertices()+1 ); } if (bValues[1] && pMesh->GetNumUVs()) { if (f[1] < 0) f[1] = (long)pMesh->GetNumUVs()+f[1]+1; TAssert ( f[1] >= 1 && f[1] < (long)pMesh->GetNumUVs()+1 ); } if (bValues[2] && pMesh->GetNumNormals()) { if (f[2] < 0) f[2] = (long)pMesh->GetNumNormals()+f[2]+1; TAssert ( f[2] >= 1 && f[2] < (long)pMesh->GetNumNormals()+1 ); } // OBJ uses 1-based indexing. // Convert to 0-based indexing. f[0]--; f[1]--; f[2]--; if (!pMesh->GetNumUVs()) f[1] = ~0; if (bValues[2] == false || !pMesh->GetNumNormals()) f[2] = ~0; pMesh->AddVertexToFace(iFace, f[0], f[1], f[2]); } } } free(pszEntireFile); m_pScene->SetWorkListener(m_pWorkListener); m_pScene->CalculateExtends(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { m_pScene->GetMesh(i)->CalculateEdgeData(); if (bSmoothingGroups || m_pScene->GetMesh(i)->GetNumNormals() == 0) m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::ReadMTL(const tstring& sFilename) { FILE* fp = tfopen(sFilename, _T("r")); if (!fp) return; if (m_pWorkListener) m_pWorkListener->SetAction(_T("Reading materials"), 0); size_t iCurrentMaterial = ~0; tstring sLine; while (fgetts(sLine, fp)) { sLine = StripWhitespace(sLine); if (sLine.length() == 0) continue; if (sLine[0] == '#') continue; eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); const tchar* pszToken = NULL; pszToken = asTokens[0].c_str(); CConversionMaterial* pMaterial = NULL; if (iCurrentMaterial != ~0) pMaterial = m_pScene->GetMaterial(iCurrentMaterial); if (tstrncmp(pszToken, _T("newmtl"), 6) == 0) { pszToken = asTokens[1].c_str(); CConversionMaterial oMaterial(pszToken, Vector(0.2f,0.2f,0.2f), Vector(0.8f,0.8f,0.8f), Vector(1,1,1), Vector(0,0,0), 1.0, 0); iCurrentMaterial = m_pScene->AddMaterial(oMaterial); } else if (tstrncmp(pszToken, _T("Ka"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecAmbient.x = stof(asTokens[1]); pMaterial->m_vecAmbient.y = stof(asTokens[2]); pMaterial->m_vecAmbient.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("Kd"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecDiffuse.x = stof(asTokens[1]); pMaterial->m_vecDiffuse.y = stof(asTokens[2]); pMaterial->m_vecDiffuse.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("Ks"), 2) == 0) { eastl::vector<tstring> asTokens; tstrtok(sLine, asTokens, _T(" ")); if (asTokens.size() == 4) { pMaterial->m_vecSpecular.x = stof(asTokens[1]); pMaterial->m_vecSpecular.y = stof(asTokens[2]); pMaterial->m_vecSpecular.z = stof(asTokens[3]); } } else if (tstrncmp(pszToken, _T("d"), 1) == 0 || tstrncmp(pszToken, _T("Tr"), 2) == 0) { pMaterial->m_flTransparency = (float)stof(asTokens[1]); } else if (tstrncmp(pszToken, _T("Ns"), 2) == 0) { pMaterial->m_flShininess = (float)stof(asTokens[1])*128/1000; } else if (tstrncmp(pszToken, _T("illum"), 5) == 0) { pMaterial->m_eIllumType = (IllumType_t)stoi(asTokens[1]); } else if (tstrncmp(pszToken, _T("map_Kd"), 6) == 0) { pszToken = asTokens[1].c_str(); FILE* fpTest = tfopen(pszToken, _T("r")); if (fpTest) { fclose(fpTest); pMaterial->m_sDiffuseTexture = tstring(pszToken); } else { tstring sDirectory = GetDirectory(sFilename); pMaterial->m_sDiffuseTexture = sprintf(tstring("%s/%s"), sDirectory.c_str(), pszToken); } } } fclose(fp); }
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; }