Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
// 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();
}
Beispiel #4
0
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();
}
Beispiel #5
0
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);
}
Beispiel #6
0
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;
}