void CAOGenerator::RenderSetupSceneNode(CConversionSceneNode* pNode, tvector<tvector<float>>& aaflVerts) { if (!pNode) return; for (size_t c = 0; c < pNode->GetNumChildren(); c++) RenderSetupSceneNode(pNode->GetChild(c), aaflVerts); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); size_t iMaterial = pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial; while (aaflVerts.size() <= iMaterial) aaflVerts.push_back(); CConversionVertex* pVertex0 = pFace->GetVertex(0); for (size_t k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } } } }
void CGeppetto::LoadMeshInstanceIntoToyPhysics(CConversionScene* pScene, CConversionMeshInstance* pMeshInstance, const Matrix4x4& mParentTransformations, CToyUtil* pToy) { if (!pMeshInstance->IsVisible()) return; CConversionMesh* pMesh = pMeshInstance->GetMesh(); size_t iVertsSize = pToy->GetNumPhysVerts(); for (size_t v = 0; v < pMesh->GetNumVertices(); v++) pToy->AddPhysVertex(mParentTransformations * pMesh->GetVertex(v)); for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { size_t k; CConversionFace* pFace = pMesh->GetFace(j); CConversionVertex* pVertex0 = pFace->GetVertex(0); for (k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); pToy->AddPhysTriangle(iVertsSize + pVertex0->v, iVertsSize + pVertex1->v, iVertsSize + pVertex2->v); } } }
void CAOGenerator::GenerateNodeByTexel(CConversionSceneNode* pNode, raytrace::CRaytracer* pTracer, size_t& iRendered) { for (size_t c = 0; c < pNode->GetNumChildren(); c++) GenerateNodeByTexel(pNode->GetChild(c), pTracer, iRendered); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); if (!pMesh->GetNumUVs()) continue; for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); if (pFace->m != ~0) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } tvector<Vector> avecPoints; tvector<size_t> aiPoints; for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMeshInstance->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[iLast], aiPoints[iEar], aiPoints[iNext], pTracer, iRendered); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); if (m_bStopGenerating) break; } GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[0], aiPoints[1], aiPoints[2], pTracer, iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } }
void CAOGenerator::GenerateByTexel() { if (m_eAOMethod == AOMETHOD_RAYTRACE) RaytraceSetupThreads(); float flTotalArea = 0; for (size_t m = 0; m < m_pScene->GetNumMeshes(); m++) { CConversionMesh* pMesh = m_pScene->GetMesh(m); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); flTotalArea += pFace->GetUVArea(); } } raytrace::CRaytracer* pTracer = NULL; if (m_eAOMethod == AOMETHOD_RAYTRACE) { m_pWorkListener->SetAction("Building tree", 0); pTracer = new raytrace::CRaytracer(m_pScene); pTracer->AddMeshesFromNode(m_pScene->GetScene(0)); pTracer->BuildTree(); srand((unsigned int)time(0)); } if (m_eAOMethod == AOMETHOD_RAYTRACE && GetNumberOfProcessors() > 1) m_pWorkListener->SetAction("Dispatching jobs", (size_t)(flTotalArea*m_iWidth*m_iHeight)); else m_pWorkListener->SetAction("Rendering", (size_t)(flTotalArea*m_iWidth*m_iHeight)); size_t iRendered = 0; if (m_pScene->GetNumScenes()) GenerateNodeByTexel(m_pScene->GetScene(0), pTracer, iRendered); if (m_eAOMethod == AOMETHOD_RAYTRACE) { RaytraceJoinThreads(); RaytraceCleanupThreads(); delete pTracer; } }
void CAOGenerator::ShadowMapSetupSceneNode(CConversionSceneNode* pNode, tvector<float>& aflVerts, bool bDepth) { if (!pNode) return; for (size_t c = 0; c < pNode->GetNumChildren(); c++) ShadowMapSetupSceneNode(pNode->GetChild(c), aflVerts, bDepth); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); if (!bDepth) { // Allow this in the depth model so that it still projects a shadow, but we don't produce a map for it. if (pFace->m != ~0 && pMeshInstance->GetMappedMaterial(pFace->m)) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } } CConversionVertex* pVertex0 = pFace->GetVertex(0); for (size_t k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex0->v), pMeshInstance->GetNormal(pVertex0->vn), pMesh->GetUV(pVertex0->vu)); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex1->v), pMeshInstance->GetNormal(pVertex1->vn), pMesh->GetUV(pVertex1->vu)); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex2->v), pMeshInstance->GetNormal(pVertex2->vn), pMesh->GetUV(pVertex2->vu)); } } } }
void LoadMeshInstanceIntoToy(CConversionScene* pScene, CConversionMeshInstance* pMeshInstance, const Matrix4x4& mParentTransformations) { if (!pMeshInstance->IsVisible()) return; CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t m = 0; m < pScene->GetNumMaterials(); m++) { for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { size_t k; CConversionFace* pFace = pMesh->GetFace(j); if (pFace->m == ~0) continue; CConversionMaterial* pMaterial = NULL; CConversionMaterialMap* pConversionMaterialMap = pMeshInstance->GetMappedMaterial(pFace->m); if (!pConversionMaterialMap) continue; if (!pConversionMaterialMap->IsVisible()) continue; if (pConversionMaterialMap->m_iMaterial != m) continue; while (g_asTextures.size() <= pConversionMaterialMap->m_iMaterial) { g_asTextures.push_back(pScene->GetMaterial(pConversionMaterialMap->m_iMaterial)->GetDiffuseTexture()); g_aaflData.push_back(); } size_t iMaterial = pConversionMaterialMap->m_iMaterial; CConversionVertex* pVertex0 = pFace->GetVertex(0); for (k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } } } }
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(); }
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 CTexelDiffuseMethod::GenerateTexel(size_t iTexel, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, raytrace::CTraceResult* tr, const Vector& vecUVPosition, raytrace::CRaytracer* pTracer) { CConversionFace* pHitFace = tr->m_pMeshInstance->GetMesh()->GetFace(tr->m_iFace); CTexture& oTexture = m_aTextures[tr->m_pMeshInstance->GetMappedMaterial(pHitFace->m)->m_iMaterial]; if (!oTexture.m_pclrData) return; CConversionMesh* pHitMesh = tr->m_pMeshInstance->GetMesh(); // TODO: Use the nearest triangle in this face. CConversionVertex* pHitV1 = pHitFace->GetVertex(0); CConversionVertex* pHitV2 = pHitFace->GetVertex(1); CConversionVertex* pHitV3 = pHitFace->GetVertex(2); Vector2D vu1 = pHitMesh->GetUV(pHitV1->vu); Vector2D vu2 = pHitMesh->GetUV(pHitV2->vu); Vector2D vu3 = pHitMesh->GetUV(pHitV3->vu); Vector v1 = tr->m_pMeshInstance->GetVertex(pHitV1->v); Vector v2 = tr->m_pMeshInstance->GetVertex(pHitV2->v); Vector v3 = tr->m_pMeshInstance->GetVertex(pHitV3->v); // Find where the world point is in UV space. // First convert to barycentric coordinates. Vector u = v2 - v1; Vector v = v3 - v1; float uu = u.Dot(u); float uv = u.Dot(v); float vv = v.Dot(v); Vector w = tr->m_vecHit - v1; float wu = w.Dot(u); float wv = w.Dot(v); float D = uv * uv - uu * vv; float b1, b2, b3; b1 = (uv * wu - uu * wv) / D; b2 = (uv * wv - vv * wu) / D; b3 = 1 - b1 - b2; // The position of the traceline's hit in (u, v) texture space Vector2D vecWorldPosition = vu1 * b1 + vu2 * b2 + vu3 * b3; // Mutex may be dead, try to bail before. if (m_pGenerator->IsStopped()) return; size_t iU = (size_t)((vecWorldPosition.x * oTexture.m_iWidth) - 0.5f); size_t iV = (size_t)((vecWorldPosition.y * oTexture.m_iHeight) - 0.5f); iU %= oTexture.m_iWidth; iV %= oTexture.m_iHeight; size_t iColorTexel; m_pGenerator->Texel(iU, iV, iColorTexel, oTexture.m_iWidth, oTexture.m_iHeight); Color clrData = oTexture.m_pclrData[iColorTexel]; m_pGenerator->GetParallelizer()->LockData(); m_avecDiffuseValues[iTexel] += Vector(clrData); m_aiDiffuseReads[iTexel]++; m_pGenerator->MarkTexelUsed(iTexel); m_pGenerator->GetParallelizer()->UnlockData(); }
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 CTexelGenerator::GenerateTriangleByTexel(CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t v1, size_t v2, size_t v3, raytrace::CRaytracer* pTracer, size_t& iRendered) { texel_data_t oJob; CConversionVertex* pV1 = pFace->GetVertex(v1); CConversionVertex* pV2 = pFace->GetVertex(v2); CConversionVertex* pV3 = pFace->GetVertex(v3); CConversionMesh* pMesh = pMeshInstance->GetMesh(); oJob.pMeshInstance = pMeshInstance; oJob.pFace = pFace; oJob.pV1 = pV1; oJob.pV2 = pV2; oJob.pV3 = pV3; oJob.pTracer = pTracer; oJob.pGenerator = this; Vector vu1 = pMesh->GetUV(pV1->vu); Vector vu2 = pMesh->GetUV(pV2->vu); Vector vu3 = pMesh->GetUV(pV3->vu); Vector vecLoUV = vu1; Vector vecHiUV = vu1; if (vu2.x < vecLoUV.x) vecLoUV.x = vu2.x; if (vu3.x < vecLoUV.x) vecLoUV.x = vu3.x; if (vu2.x > vecHiUV.x) vecHiUV.x = vu2.x; if (vu3.x > vecHiUV.x) vecHiUV.x = vu3.x; if (vu2.y < vecLoUV.y) vecLoUV.y = vu2.y; if (vu3.y < vecLoUV.y) vecLoUV.y = vu3.y; if (vu2.y > vecHiUV.y) vecHiUV.y = vu2.y; if (vu3.y > vecHiUV.y) vecHiUV.y = vu3.y; size_t iLoX = (size_t)(vecLoUV.x * m_iWidth); size_t iLoY = (size_t)(vecLoUV.y * m_iHeight); size_t iHiX = (size_t)(vecHiUV.x * m_iWidth); size_t iHiY = (size_t)(vecHiUV.y * m_iHeight); for (size_t i = iLoX; i <= iHiX; i++) { for (size_t j = iLoY; j <= iHiY; j++) { oJob.x = i; oJob.y = j; m_pWorkParallelizer->AddJob(&oJob, sizeof(oJob)); if (m_pWorkListener) m_pWorkListener->WorkProgress(++iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } }
void CTexelGenerator::FindHiResMeshLocation(CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, size_t i, size_t j, raytrace::CRaytracer* pTracer) { CConversionMesh* pMesh = pMeshInstance->GetMesh(); Vector vu1 = pMesh->GetUV(pV1->vu); Vector vu2 = pMesh->GetUV(pV2->vu); Vector vu3 = pMesh->GetUV(pV3->vu); float flU = ((float)i + 0.5f)/(float)m_iWidth; float flV = ((float)j + 0.5f)/(float)m_iHeight; bool bInside = PointInTriangle(Vector(flU,flV,0), vu1, vu2, vu3); if (!bInside) return; Vector v1 = pMeshInstance->GetVertex(pV1->v); Vector v2 = pMeshInstance->GetVertex(pV2->v); Vector v3 = pMeshInstance->GetVertex(pV3->v); // Find where the UV is in world space. // First build 2x2 a "matrix" of the UV values. float mta = vu2.x - vu1.x; float mtb = vu3.x - vu1.x; float mtc = vu2.y - vu1.y; float mtd = vu3.y - vu1.y; // Invert it. float d = mta*mtd - mtb*mtc; float mtia = mtd / d; float mtib = -mtb / d; float mtic = -mtc / d; float mtid = mta / d; // Now build a 2x3 "matrix" of the vertices. float mva = v2.x - v1.x; float mvb = v3.x - v1.x; float mvc = v2.y - v1.y; float mvd = v3.y - v1.y; float mve = v2.z - v1.z; float mvf = v3.z - v1.z; // Multiply them together. // [a b] [a b] [a b] // [c d] * [c d] = [c d] // [e f] [e f] // Really wish I had a matrix math library about now! float mra = mva*mtia + mvb*mtic; float mrb = mva*mtib + mvb*mtid; float mrc = mvc*mtia + mvd*mtic; float mrd = mvc*mtib + mvd*mtid; float mre = mve*mtia + mvf*mtic; float mrf = mve*mtib + mvf*mtid; // These vectors should be the U and V axis in world space. Vector vecUAxis(mra, mrc, mre); Vector vecVAxis(mrb, mrd, mrf); Vector vecUVOrigin = v1 - vecUAxis * vu1.x - vecVAxis * vu1.y; Vector vecUVPosition = vecUVOrigin + vecUAxis * flU + vecVAxis * flV; Vector vecNormal = pFace->GetNormal(vecUVPosition, pMeshInstance); size_t iTexel; Texel(i, j, iTexel, false); // Maybe use a closest-poly check here to eliminate the need for some raytracing? raytrace::CTraceResult trFront; bool bHitFront = pTracer->Raytrace(Ray(vecUVPosition, vecNormal), &trFront); raytrace::CTraceResult trBack; bool bHitBack = pTracer->Raytrace(Ray(vecUVPosition, -vecNormal), &trBack); #ifdef NORMAL_DEBUG GetParallelizer()->LockData(); if (bHitFront && (vecUVPosition - trFront.m_vecHit).LengthSqr() > 0.001f) SMAKWindow()->AddDebugLine(vecUVPosition, trFront.m_vecHit); if (bHitBack && (vecUVPosition - trBack.m_vecHit).LengthSqr() > 0.001f) SMAKWindow()->AddDebugLine(vecUVPosition, trBack.m_vecHit); GetParallelizer()->UnlockData(); #endif if (!bHitBack && !bHitFront) return; raytrace::CTraceResult* trFinal; if (bHitFront && !bHitBack) trFinal = &trFront; else if (bHitBack && !bHitFront) trFinal = &trBack; else { float flHitFront = (vecUVPosition - trFront.m_vecHit).LengthSqr(); float flHitBack = (vecUVPosition - trBack.m_vecHit).LengthSqr(); if (flHitFront < flHitBack) trFinal = &trFront; else trFinal = &trBack; } #ifdef NORMAL_DEBUG GetParallelizer()->LockData(); // SMAKWindow()->AddDebugLine(vecUVPosition, vecUVPosition+vecHitNormal); if (bHitFront && (vecUVPosition - trFront.m_vecHit).LengthSqr() > 0.001f) SMAKWindow()->AddDebugLine(trFront.m_vecHit, trFront.m_vecHit + trFront.m_pFace->GetNormal(trFront.m_vecHit, trFront.m_pMeshInstance)); if (bHitBack && (vecUVPosition - trBack.m_vecHit).LengthSqr() > 0.001f) SMAKWindow()->AddDebugLine(trBack.m_vecHit, trBack.m_vecHit + trBack.m_pFace->GetNormal(trBack.m_vecHit, trBack.m_pMeshInstance)); GetParallelizer()->UnlockData(); #endif for (size_t i = 0; i < m_apMethods.size(); i++) { m_apMethods[i]->GenerateTexel(iTexel, pMeshInstance, pFace, pV1, pV2, pV3, trFinal, vecUVPosition, pTracer); } }
void CAOGenerator::GenerateTriangleByTexel(CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t v1, size_t v2, size_t v3, raytrace::CRaytracer* pTracer, size_t& iRendered) { CConversionVertex* pV1 = pFace->GetVertex(v1); CConversionVertex* pV2 = pFace->GetVertex(v2); CConversionVertex* pV3 = pFace->GetVertex(v3); CConversionMesh* pMesh = pMeshInstance->GetMesh(); Vector vu1 = pMesh->GetUV(pV1->vu); Vector vu2 = pMesh->GetUV(pV2->vu); Vector vu3 = pMesh->GetUV(pV3->vu); Vector vecLoUV = vu1; Vector vecHiUV = vu1; if (vu2.x < vecLoUV.x) vecLoUV.x = vu2.x; if (vu3.x < vecLoUV.x) vecLoUV.x = vu3.x; if (vu2.x > vecHiUV.x) vecHiUV.x = vu2.x; if (vu3.x > vecHiUV.x) vecHiUV.x = vu3.x; if (vu2.y < vecLoUV.y) vecLoUV.y = vu2.y; if (vu3.y < vecLoUV.y) vecLoUV.y = vu3.y; if (vu2.y > vecHiUV.y) vecHiUV.y = vu2.y; if (vu3.y > vecHiUV.y) vecHiUV.y = vu3.y; size_t iLoX = (size_t)(vecLoUV.x * m_iWidth); size_t iLoY = (size_t)(vecLoUV.y * m_iHeight); size_t iHiX = (size_t)(vecHiUV.x * m_iWidth); size_t iHiY = (size_t)(vecHiUV.y * m_iHeight); for (size_t i = iLoX; i <= iHiX; i++) { for (size_t j = iLoY; j <= iHiY; j++) { float flU = ((float)i + 0.5f)/(float)m_iWidth; float flV = ((float)j + 0.5f)/(float)m_iHeight; bool bInside = PointInTriangle(Vector(flU,flV,0), vu1, vu2, vu3); if (!bInside) continue; Vector v1 = pMeshInstance->GetVertex(pV1->v); Vector v2 = pMeshInstance->GetVertex(pV2->v); Vector v3 = pMeshInstance->GetVertex(pV3->v); Vector vn1 = pMeshInstance->GetNormal(pV1->vn); Vector vn2 = pMeshInstance->GetNormal(pV2->vn); Vector vn3 = pMeshInstance->GetNormal(pV3->vn); // Find where the UV is in world space. // First build 2x2 a "matrix" of the UV values. float mta = vu2.x - vu1.x; float mtb = vu3.x - vu1.x; float mtc = vu2.y - vu1.y; float mtd = vu3.y - vu1.y; // Invert it. float d = mta*mtd - mtb*mtc; float mtia = mtd / d; float mtib = -mtb / d; float mtic = -mtc / d; float mtid = mta / d; // Now build a 2x3 "matrix" of the vertices. float mva = v2.x - v1.x; float mvb = v3.x - v1.x; float mvc = v2.y - v1.y; float mvd = v3.y - v1.y; float mve = v2.z - v1.z; float mvf = v3.z - v1.z; // Multiply them together. // [a b] [a b] [a b] // [c d] * [c d] = [c d] // [e f] [e f] // Really wish I had a matrix math library about now! float mra = mva*mtia + mvb*mtic; float mrb = mva*mtib + mvb*mtid; float mrc = mvc*mtia + mvd*mtic; float mrd = mvc*mtib + mvd*mtid; float mre = mve*mtia + mvf*mtic; float mrf = mve*mtib + mvf*mtid; // These vectors should be the U and V axis in world space. Vector vecUAxis(mra, mrc, mre); Vector vecVAxis(mrb, mrd, mrf); Vector vecUVOrigin = v1 - vecUAxis * vu1.x - vecVAxis * vu1.y; Vector vecUVPosition = vecUVOrigin + vecUAxis * flU + vecVAxis * flV; Vector vecNormal; if (m_bCreaseEdges) vecNormal = pFace->GetNormal(); else { float wv1 = DistanceToLine(vecUVPosition, v2, v3) / DistanceToLine(v1, v2, v3); float wv2 = DistanceToLine(vecUVPosition, v1, v3) / DistanceToLine(v2, v1, v3); float wv3 = DistanceToLine(vecUVPosition, v1, v2) / DistanceToLine(v3, v1, v2); vecNormal = vn1 * wv1 + vn2 * wv2 + vn3 * wv3; } if (ao_debug.GetInt() > 1) SMAKWindow()->AddDebugLine(vecUVPosition, vecUVPosition + vecNormal/2); size_t iTexel; if (!Texel(i, j, iTexel, false)) continue; if (m_eAOMethod == AOMETHOD_RENDER) { // Render the scene from this location m_avecShadowValues[iTexel] += RenderSceneFromPosition(vecUVPosition, vecNormal, pFace); } else if (m_eAOMethod == AOMETHOD_RAYTRACE) { RaytraceSceneMultithreaded(pTracer, vecUVPosition, vecNormal, pMeshInstance, pFace, iTexel); } m_aiShadowReads[iTexel]++; m_bPixelMask[iTexel] = true; m_pWorkListener->WorkProgress(++iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } }
void LoadMesh(CConversionScene* pScene, size_t iMesh) { TAssert(iMesh < pScene->GetNumMeshes()); if (iMesh >= pScene->GetNumMeshes()) return; // Reserve space for n+1, the last one represents the default material. g_aaflData.resize(pScene->GetNumMaterials()+1); tvector<Vector> avecPoints; tvector<size_t> aiPoints; CConversionMesh* pMesh = pScene->GetMesh(iMesh); for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { CConversionFace* pFace = pMesh->GetFace(j); size_t iMaterial = pFace->m; if (iMaterial == ~0) iMaterial = pScene->GetNumMaterials(); CConversionVertex* pVertex0 = pFace->GetVertex(0); CConversionVertex* pVertex1 = pFace->GetVertex(1); CConversionVertex* pLastVertex = pFace->GetVertex(pFace->GetNumVertices()-1); avecPoints.clear(); aiPoints.clear(); for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMesh->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } CConversionVertex* pVertex2; while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; pVertex0 = pFace->GetVertex(aiPoints[iLast]); pVertex1 = pFace->GetVertex(aiPoints[iEar]); pVertex2 = pFace->GetVertex(aiPoints[iNext]); AddVertex(iMaterial, pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); } TAssert(aiPoints.size() == 3); if (aiPoints.size() != 3) continue; pVertex0 = pFace->GetVertex(aiPoints[0]); pVertex1 = pFace->GetVertex(aiPoints[1]); pVertex2 = pFace->GetVertex(aiPoints[2]); AddVertex(iMaterial, pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } }
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; }
bool CModelConverter::ReadDAE(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FCollada::Initialize(); FCDocument* pDoc = FCollada::NewTopDocument(); if (m_pWorkListener) m_pWorkListener->SetAction("Reading file", 0); if (FCollada::LoadDocumentFromFile(pDoc, convert_to_fstring(sFilename))) { size_t i; FCDocumentTools::StandardizeUpAxisAndLength(pDoc, FMVector3(0, 1, 0)); FCDMaterialLibrary* pMatLib = pDoc->GetMaterialLibrary(); size_t iEntities = pMatLib->GetEntityCount(); if (m_pWorkListener) m_pWorkListener->SetAction("Reading materials", iEntities); for (i = 0; i < iEntities; ++i) { FCDMaterial* pColladaMaterial = pMatLib->GetEntity(i); FCDEffect* pEffect = pColladaMaterial->GetEffect(); size_t iMaterial = m_pScene->AddMaterial(convert_from_fstring(pColladaMaterial->GetName())); CConversionMaterial* pMaterial = m_pScene->GetMaterial(iMaterial); if (pEffect->GetProfileCount() < 1) continue; FCDEffectProfile* pEffectProfile = pEffect->GetProfile(0); FUDaeProfileType::Type eProfileType = pEffectProfile->GetType(); if (eProfileType == FUDaeProfileType::COMMON) { FCDEffectStandard* pStandardProfile = dynamic_cast<FCDEffectStandard*>(pEffectProfile); if (pStandardProfile) { pMaterial->m_vecAmbient = Vector((float*)pStandardProfile->GetAmbientColor()); pMaterial->m_vecDiffuse = Vector((float*)pStandardProfile->GetDiffuseColor()); pMaterial->m_vecSpecular = Vector((float*)pStandardProfile->GetSpecularColor()); pMaterial->m_vecEmissive = Vector((float*)pStandardProfile->GetEmissionColor()); pMaterial->m_flShininess = pStandardProfile->GetShininess(); } } for (size_t j = 0; j < pEffectProfile->GetEffectParameterCount(); j++) { FCDEffectParameter* pEffectParameter = pEffectProfile->GetEffectParameter(j); FCDEffectParameter::Type eType = pEffectParameter->GetType(); if (eType == FCDEffectParameter::SAMPLER) { FCDEffectParameterSampler* pSampler = dynamic_cast<FCDEffectParameterSampler*>(pEffectParameter); if (pSampler) { FCDEffectParameterSurface* pSurface = pSampler->GetSurface(); if (pSurface) { if (pSurface->GetImageCount()) { // Christ Collada why do you have to make things so damn complicated? FCDImage* pImage = pSurface->GetImage(0); pMaterial->m_sDiffuseTexture = convert_from_fstring(pImage->GetFilename()); // Fix up a bug in the Max Collada exporter if (pMaterial->m_sDiffuseTexture.startswith("\\\\C\\")) pMaterial->m_sDiffuseTexture = "C:\\" + pMaterial->m_sDiffuseTexture.substr(4); else if (pMaterial->m_sDiffuseTexture.startswith("\\\\D\\")) pMaterial->m_sDiffuseTexture = "D:\\" + pMaterial->m_sDiffuseTexture.substr(4); } } } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i+1); } FCDGeometryLibrary* pGeoLib = pDoc->GetGeometryLibrary(); iEntities = pGeoLib->GetEntityCount(); if (m_pWorkListener) m_pWorkListener->SetAction("Loading entities", iEntities); for (i = 0; i < iEntities; ++i) { FCDGeometry* pGeometry = pGeoLib->GetEntity(i); if (pGeometry->IsMesh()) { size_t j; size_t iMesh = m_pScene->AddMesh(convert_from_fstring(pGeometry->GetName())); CConversionMesh* pMesh = m_pScene->GetMesh(iMesh); pMesh->AddBone(convert_from_fstring(pGeometry->GetName())); FCDGeometryMesh* pGeoMesh = pGeometry->GetMesh(); FCDGeometrySource* pPositionSource = pGeoMesh->GetPositionSource(); size_t iVertexCount = pPositionSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pPositionSource->GetValue(j); pMesh->AddVertex(pflValues[0], pflValues[1], pflValues[2]); } FCDGeometrySource* pNormalSource = pGeoMesh->FindSourceByType(FUDaeGeometryInput::NORMAL); if (pNormalSource) { iVertexCount = pNormalSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pNormalSource->GetValue(j); pMesh->AddNormal(pflValues[0], pflValues[1], pflValues[2]); } } FCDGeometrySource* pUVSource = pGeoMesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD); if (pUVSource) { iVertexCount = pUVSource->GetValueCount(); for (j = 0; j < iVertexCount; j++) { const float* pflValues = pUVSource->GetValue(j); pMesh->AddUV(pflValues[0], pflValues[1]); } } for (j = 0; j < pGeoMesh->GetPolygonsCount(); j++) { FCDGeometryPolygons* pPolygons = pGeoMesh->GetPolygons(j); FCDGeometryPolygonsInput* pPositionInput = pPolygons->FindInput(FUDaeGeometryInput::POSITION); FCDGeometryPolygonsInput* pNormalInput = pPolygons->FindInput(FUDaeGeometryInput::NORMAL); FCDGeometryPolygonsInput* pUVInput = pPolygons->FindInput(FUDaeGeometryInput::TEXCOORD); size_t iPositionCount = pPositionInput->GetIndexCount(); uint32* pPositions = pPositionInput->GetIndices(); size_t iNormalCount = 0; uint32* pNormals = NULL; if (pNormalInput) { iNormalCount = pNormalInput->GetIndexCount(); pNormals = pNormalInput->GetIndices(); } size_t iUVCount = 0; uint32* pUVs = NULL; if (pUVInput) { iUVCount = pUVInput->GetIndexCount(); pUVs = pUVInput->GetIndices(); } fm::stringT<fchar> sMaterial = pPolygons->GetMaterialSemantic(); size_t iCurrentMaterial = pMesh->AddMaterialStub(convert_from_fstring(sMaterial)); if (pPolygons->TestPolyType() == 3) { // All triangles! for (size_t k = 0; k < iPositionCount; k+=3) { size_t iFace = pMesh->AddFace(iCurrentMaterial); pMesh->AddVertexToFace(iFace, pPositions[k+0], pUVs?pUVs[k+0]:~0, pNormals?pNormals[k+0]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+1], pUVs?pUVs[k+1]:~0, pNormals?pNormals[k+1]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+2], pUVs?pUVs[k+2]:~0, pNormals?pNormals[k+2]:~0); } } else if (pPolygons->TestPolyType() == 4) { // All quads! for (size_t k = 0; k < iPositionCount; k+=4) { size_t iFace = pMesh->AddFace(iCurrentMaterial); pMesh->AddVertexToFace(iFace, pPositions[k+0], pUVs?pUVs[k+0]:~0, pNormals?pNormals[k+0]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+1], pUVs?pUVs[k+1]:~0, pNormals?pNormals[k+1]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+2], pUVs?pUVs[k+2]:~0, pNormals?pNormals[k+2]:~0); pMesh->AddVertexToFace(iFace, pPositions[k+3], pUVs?pUVs[k+3]:~0, pNormals?pNormals[k+3]:~0); } } else { size_t iFaces = pPolygons->GetFaceCount(); for (size_t k = 0; k < iFaces; k++) { size_t iFace = pMesh->AddFace(iCurrentMaterial); size_t o = pPolygons->GetFaceVertexOffset(k); size_t iFaceVertexCount = pPolygons->GetFaceVertexCount(k); for (size_t v = 0; v < iFaceVertexCount; v++) pMesh->AddVertexToFace(iFace, pPositions[o+v], pUVs?pUVs[o+v]:~0, pNormals?pNormals[o+v]:~0); } } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i+1); } FCDVisualSceneNodeLibrary* pVisualScenes = pDoc->GetVisualSceneLibrary(); iEntities = pVisualScenes->GetEntityCount(); for (i = 0; i < iEntities; ++i) { FCDSceneNode* pNode = pVisualScenes->GetEntity(i); size_t iScene = m_pScene->AddScene(convert_from_fstring(pNode->GetName())); ReadDAESceneTree(pNode, m_pScene->GetScene(iScene)); } } else { printf("Oops! Some kind of error happened!\n"); return false; } m_pScene->SetWorkListener(m_pWorkListener); m_pScene->CalculateExtends(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { if (m_bWantEdges) m_pScene->GetMesh(i)->CalculateEdgeData(); if (m_pScene->GetMesh(i)->GetNumNormals() == 0) m_pScene->GetMesh(i)->CalculateVertexNormals(); m_pScene->GetMesh(i)->CalculateVertexTangents(); } pDoc->Release(); FCollada::Release(); if (m_pWorkListener) m_pWorkListener->EndProgress(); return true; }
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(); }
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(); }
void CModelConverter::WriteSMD(size_t iMesh, const tstring& sFilename) { CConversionMesh* pMesh = m_pScene->GetMesh(iMesh); tstring sFile; if (sFilename.length()) { sFile.append(sFilename); sFile.append(_T("_")); } sFile.append(pMesh->GetBoneName(0)); sFile = GetFilename(sFile.c_str()); sFile.append(_T(".smd")); FILE* fp = tfopen(sFile, _T("w")); // SMD file format: http://developer.valvesoftware.com/wiki/SMD // Header section fprintf(fp, "version 1\n\n"); // Nodes section fprintf(fp, "nodes\n"); // Only bothering with one node, we're only doing static props with this code for now. fprintf(fp, "0 \"%s\" -1\n", convertstring<tchar, char>(pMesh->GetBoneName(0)).c_str()); fprintf(fp, "end\n\n"); // Skeleton section fprintf(fp, "skeleton\n"); fprintf(fp, "time 0\n"); fprintf(fp, "0 0.000000 0.000000 0.000000 1.570796 0.000000 0.0000001\n"); fprintf(fp, "end\n\n"); fprintf(fp, "triangles\n"); for (size_t i = 0; i < pMesh->GetNumFaces(); i++) { CConversionFace* pFace = pMesh->GetFace(i); if (!pFace->GetNumVertices()) { printf("WARNING! Found a face with no vertices.\n"); continue; } CConversionVertex* pV1 = pFace->GetVertex(0); for (size_t j = 0; j < pFace->GetNumVertices()-2; j++) { CConversionVertex* pV2 = pFace->GetVertex(j+1); CConversionVertex* pV3 = pFace->GetVertex(j+2); Vector v1 = pMesh->GetVertex(pV1->v); Vector v2 = pMesh->GetVertex(pV2->v); Vector v3 = pMesh->GetVertex(pV3->v); Vector n1 = pMesh->GetNormal(pV1->vn); Vector n2 = pMesh->GetNormal(pV2->vn); Vector n3 = pMesh->GetNormal(pV3->vn); Vector uv1 = pMesh->GetUV(pV1->vu); Vector uv2 = pMesh->GetUV(pV2->vu); Vector uv3 = pMesh->GetUV(pV3->vu); // Material name size_t iMaterial = pFace->m; if (iMaterial == ((size_t)~0) || !m_pScene->GetMaterial(iMaterial)) { printf("ERROR! Can't find a material for a triangle.\n"); fprintf(fp, "error\n"); } else fprintf(fp, "%s\n", convertstring<tchar, char>(m_pScene->GetMaterial(iMaterial)->GetName()).c_str()); // <int|Parent bone> <float|PosX PosY PosZ> <normal|NormX NormY NormZ> <normal|U V> // Studio coordinates are not the same as game coordinates. Studio (x, y, z) is game (x, -z, y) and vice versa. fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v1.x, -v1.z, v1.y, n1.x, -n1.z, n1.y, uv1.x, uv1.y); fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v2.x, -v2.z, v2.y, n2.x, -n2.z, n2.y, uv2.x, uv2.y); fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v3.x, -v3.z, v3.y, n3.x, -n3.z, n3.y, uv3.x, uv3.y); } } fprintf(fp, "end\n"); fclose(fp); }
int main(int argc, const char* argv[]) { if (argc < 2) { printf("I need a file to convert!\n"); return 0; } size_t iFileLength = strlen(argv[1]); const char* pszExtension = argv[1]+iFileLength-4; CConversionScene s; CModelConverter c(&s); tstring sFile = argv[1]; if (strcmp(pszExtension, ".obj") == 0) { printf("Reading the OBJ... "); c.ReadOBJ(sFile); } else if (strcmp(pszExtension, ".sia") == 0) { printf("Reading the Silo ASCII file... "); c.ReadSIA(sFile); } else if (strcmp(pszExtension, ".dae") == 0) { printf("Reading the Collada .dae file... "); c.ReadDAE(sFile); } printf("Done.\n"); printf("\n"); printf("-------------\n"); printf("Materials : %d\n", s.GetNumMaterials()); printf("Meshes : %d\n", s.GetNumMeshes()); printf("\n"); for (size_t i = 0; i < s.GetNumMeshes(); i++) { CConversionMesh* pMesh = s.GetMesh(i); printf("-------------\n"); printf("Mesh: %s\n", pMesh->GetBoneName(0)); printf("Vertices : %d\n", pMesh->GetNumVertices()); printf("Normals : %d\n", pMesh->GetNumNormals()); printf("UVs : %d\n", pMesh->GetNumUVs()); printf("Bones : %d\n", pMesh->GetNumBones()); printf("Faces : %d\n", pMesh->GetNumFaces()); printf("\n"); } printf("Writing the SMD... "); c.WriteSMDs(); printf("Done.\n"); printf("\n"); printf("Press enter to continue...\n"); getchar(); return 0; }
void CTexelGenerator::Generate() { for (size_t i = 0; i < m_apMethods.size(); i++) m_apMethods[i]->PreGenerate(); if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction("Building tree", 0); } if (SMAKWindow()) SMAKWindow()->ClearDebugLines(); memset(&m_abTexelMask[0], 0, m_iWidth*m_iHeight*sizeof(bool)); m_bIsGenerating = true; m_bStopGenerating = false; m_bDoneGenerating = false; raytrace::CRaytracer* pTracer = NULL; pTracer = new raytrace::CRaytracer(m_pScene); for (size_t m = 0; m < m_apHiRes.size(); m++) pTracer->AddMeshInstance(m_apHiRes[m]); pTracer->BuildTree(); m_pWorkParallelizer = new CParallelizer((JobCallback)::ComputeAtTexel); m_pWorkParallelizer->Start(); float flTotalArea = 0; for (size_t m = 0; m < m_pScene->GetNumMeshes(); m++) { CConversionMesh* pMesh = m_pScene->GetMesh(m); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); flTotalArea += pFace->GetUVArea(); } } if (m_pWorkListener) m_pWorkListener->SetAction("Dispatching jobs", (size_t)(flTotalArea*m_iWidth*m_iHeight)); size_t iRendered = 0; tvector<Vector> avecPoints; tvector<size_t> aiPoints; for (size_t i = 0; i < m_apLoRes.size(); i++) { CConversionMeshInstance* pMeshInstance = m_apLoRes[i]; if (!pMeshInstance->GetMesh()->GetNumUVs()) continue; for (size_t f = 0; f < pMeshInstance->GetMesh()->GetNumFaces(); f++) { CConversionFace* pFace = pMeshInstance->GetMesh()->GetFace(f); if (pFace->m != ~0) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } avecPoints.clear(); aiPoints.clear(); for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMeshInstance->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[iLast], aiPoints[iEar], aiPoints[iNext], pTracer, iRendered); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); if (m_bStopGenerating) break; } GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[0], aiPoints[1], aiPoints[2], pTracer, iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } m_pWorkParallelizer->FinishJobs(); if (m_pWorkListener) m_pWorkListener->SetAction("Rendering", m_pWorkParallelizer->GetJobsTotal()); while (true) { if (m_pWorkParallelizer->AreAllJobsDone()) break; if (m_pWorkListener) m_pWorkListener->WorkProgress(m_pWorkParallelizer->GetJobsDone()); if (m_bStopGenerating) break; } delete m_pWorkParallelizer; delete pTracer; for (size_t i = 0; i < m_apMethods.size(); i++) m_apMethods[i]->PostGenerate(); if (!m_bStopGenerating) m_bDoneGenerating = true; m_bIsGenerating = false; // One last call to let them know we're done. if (m_pWorkListener) m_pWorkListener->EndProgress(); }