Exemple #1
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void OFFImporter::InternReadFile( const std::string& pFile, 
								 aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw new ImportErrorException( "Failed to open OFF file " + pFile + ".");

	unsigned int fileSize = (unsigned int)file->FileSize();

	// allocate storage and copy the contents of the file to a memory buffer
	std::vector<char> mBuffer2(fileSize+1);
	file->Read(&mBuffer2[0], 1, fileSize);
	mBuffer2[fileSize] = '\0';
	const char* buffer = &mBuffer2[0];

	char line[4096];
	GetNextLine(buffer,line);
	if ('O' == line[0])GetNextLine(buffer,line); // skip the 'OFF' line

	const char* sz = line; SkipSpaces(&sz);
	const unsigned int numVertices = strtol10(sz,&sz);SkipSpaces(&sz);
	const unsigned int numFaces = strtol10(sz,&sz);

	pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
	aiMesh* mesh = pScene->mMeshes[0] = new aiMesh();
	aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces];

	std::vector<aiVector3D> tempPositions(numVertices);

	// now read all vertex lines
	for (unsigned int i = 0; i< numVertices;++i)
	{
		if(!GetNextLine(buffer,line))
		{
			DefaultLogger::get()->error("OFF: The number of verts in the header is incorrect");
			break;
		}
		aiVector3D& v = tempPositions[i];

		sz = line; SkipSpaces(&sz);
		sz = fast_atof_move(sz,(float&)v.x); SkipSpaces(&sz);
		sz = fast_atof_move(sz,(float&)v.y); SkipSpaces(&sz);
		fast_atof_move(sz,(float&)v.z);
	}

	
	// First find out how many vertices we'll need
	const char* old = buffer;
	for (unsigned int i = 0; i< mesh->mNumFaces;++i)
	{
		if(!GetNextLine(buffer,line))
		{
			DefaultLogger::get()->error("OFF: The number of faces in the header is incorrect");
			break;
		}
		sz = line;SkipSpaces(&sz);
		if(!(faces->mNumIndices = strtol10(sz,&sz)) || faces->mNumIndices > 9)
		{
			DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
			--mesh->mNumFaces;
			continue;
		}
		mesh->mNumVertices += faces->mNumIndices;
		++faces;
	}

	if (!mesh->mNumVertices)
		throw new ImportErrorException("OFF: There are no valid faces");

	// allocate storage for the output vertices
	aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];

	// second: now parse all face indices
	buffer = old;faces = mesh->mFaces;
	for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
	{
		if(!GetNextLine(buffer,line))break;

		unsigned int idx;
		sz = line;SkipSpaces(&sz);
		if(!(idx = strtol10(sz,&sz)) || idx > 9)
			continue;

		faces->mIndices = new unsigned int [faces->mNumIndices];
		for (unsigned int m = 0; m < faces->mNumIndices;++m)
		{
			SkipSpaces(&sz);
			if ((idx = strtol10(sz,&sz)) >= numVertices)
			{
				DefaultLogger::get()->error("OFF: Vertex index is out of range");
				idx = numVertices-1;
			}
			faces->mIndices[m] = p++;
			*verts++ = tempPositions[idx];
		}
		++i;
		++faces;
	}
	
	// generate the output node graph
	pScene->mRootNode = new aiNode();
	pScene->mRootNode->mName.Set("<OFFRoot>");
	pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes = 1];
	pScene->mRootNode->mMeshes[0] = 0;

	// generate a default material
	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = 1];
	MaterialHelper* pcMat = new MaterialHelper();

	aiColor4D clr(0.6f,0.6f,0.6f,1.0f);
	pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
	pScene->mMaterials[0] = pcMat;

	const int twosided =1;
	pcMat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED);
}
Exemple #2
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void RAWImporter::InternReadFile( const std::string& pFile, 
	aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw new ImportErrorException( "Failed to open RAW file " + pFile + ".");

	unsigned int fileSize = (unsigned int)file->FileSize();

	// allocate storage and copy the contents of the file to a memory buffer
	// (terminate it with zero)
	std::vector<char> mBuffer2(fileSize+1);
	
	file->Read(&mBuffer2[0], 1, fileSize);
	mBuffer2[fileSize] = '\0';
	const char* buffer = &mBuffer2[0];

	// list of groups loaded from the file
	std::vector< GroupInformation > outGroups(1,GroupInformation("<default>"));
	std::vector< GroupInformation >::iterator curGroup = outGroups.begin();

	// now read all lines
	char line[4096];
	while (GetNextLine(buffer,line))
	{
		// if the line starts with a non-numeric identifier, it marks
		// the beginning of a new group
		const char* sz = line;SkipSpaces(&sz);
		if (IsLineEnd(*sz))continue;
		if (!IsNumeric(*sz))
		{
			const char* sz2 = sz;
			while (!IsSpaceOrNewLine(*sz2))++sz2;
			const unsigned int length = (unsigned int)(sz2-sz);

			// find an existing group with this name
			for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
				it != end;++it)
			{
				if (length == (*it).name.length() && !::strcmp(sz,(*it).name.c_str()))
				{
					curGroup = it;sz2 = NULL;
					break;
				}
			}
			if (sz2)
			{
				outGroups.push_back(GroupInformation(std::string(sz,length)));
				curGroup = outGroups.end()-1;
			}
		}
		else
		{
			// there can be maximally 12 floats plus an extra texture file name
			float data[12];
			unsigned int num;
			for (num = 0; num < 12;++num)
			{
				if(!SkipSpaces(&sz) || !IsNumeric(*sz))break;
				sz = fast_atof_move(sz,data[num]);
			}
			if (num != 12 && num != 9)
			{
				DefaultLogger::get()->error("A line may have either 9 or 12 floats and an optional texture");
				continue;
			}

			MeshInformation* output = NULL;

			const char* sz2 = sz;
			unsigned int length;
			if (!IsLineEnd(*sz))
			{
				while (!IsSpaceOrNewLine(*sz2))++sz2;
				length = (unsigned int)(sz2-sz);
			}
			else if (9 == num)
			{
				sz = "%default%";
				length = 9;
			}
			else 
			{
				sz = "";
				length = 0;
			}

			// search in the list of meshes whether we have one with this texture
			for (std::vector< MeshInformation >::iterator it = (*curGroup).meshes.begin(),
				end = (*curGroup).meshes.end(); it != end; ++it)
			{
				if (length == (*it).name.length() && (length ? !::strcmp(sz,(*it).name.c_str()) : true))
				{
					output = &(*it);
					break;
				}
			}
			// if we don't have the mesh, create it
			if (!output)
			{
				(*curGroup).meshes.push_back(MeshInformation(std::string(sz,length)));
				output = &((*curGroup).meshes.back());
			}
			if (12 == num)
			{
				aiColor4D v(data[0],data[1],data[2],1.0f);
				output->colors.push_back(v);
				output->colors.push_back(v);
				output->colors.push_back(v);

				output->vertices.push_back(aiVector3D(data[3],data[4],data[5]));
				output->vertices.push_back(aiVector3D(data[6],data[7],data[8]));
				output->vertices.push_back(aiVector3D(data[9],data[10],data[11]));
			}
			else
			{
				output->vertices.push_back(aiVector3D(data[0],data[1],data[2]));
				output->vertices.push_back(aiVector3D(data[3],data[4],data[5]));
				output->vertices.push_back(aiVector3D(data[6],data[7],data[8]));
			}
		}
	}

	pScene->mRootNode = new aiNode();
	pScene->mRootNode->mName.Set("<RawRoot>");

	// count the number of valid groups
	// (meshes can't be empty)
	for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
		it != end;++it)
	{
		if (!(*it).meshes.empty())
		{
			++pScene->mRootNode->mNumChildren; 
			pScene->mNumMeshes += (unsigned int)(*it).meshes.size();
		}
	}

	if (!pScene->mNumMeshes)
	{
		throw new ImportErrorException("RAW: No meshes loaded. The file seems to be corrupt or empty.");
	}

	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
	aiNode** cc;
	if (1 == pScene->mRootNode->mNumChildren)
	{
		cc = &pScene->mRootNode;
		pScene->mRootNode->mNumChildren = 0;
	}
	else cc = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];

	pScene->mNumMaterials = pScene->mNumMeshes;
	aiMaterial** mats = pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];

	unsigned int meshIdx = 0;
	for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
		it != end;++it)
	{
		if ((*it).meshes.empty())continue;
		
		aiNode* node;
		if (pScene->mRootNode->mNumChildren)
		{
			node = *cc = new aiNode();
			node->mParent = pScene->mRootNode;
		}
		else node = *cc;++cc;
		node->mName.Set((*it).name);

		// add all meshes
		node->mNumMeshes = (unsigned int)(*it).meshes.size();
		unsigned int* pi = node->mMeshes = new unsigned int[ node->mNumMeshes ];
		for (std::vector< MeshInformation >::iterator it2 = (*it).meshes.begin(),
			end2 = (*it).meshes.end(); it2 != end2; ++it2)
		{
			ai_assert(!(*it2).vertices.empty());

			// allocate the mesh
			*pi++ = meshIdx;
			aiMesh* mesh = pScene->mMeshes[meshIdx] = new aiMesh();
			mesh->mMaterialIndex = meshIdx++;

			mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;

			// allocate storage for the vertex components and copy them
			mesh->mNumVertices = (unsigned int)(*it2).vertices.size();
			mesh->mVertices = new aiVector3D[ mesh->mNumVertices ];
			::memcpy(mesh->mVertices,&(*it2).vertices[0],sizeof(aiVector3D)*mesh->mNumVertices);

			if ((*it2).colors.size())
			{
				ai_assert((*it2).colors.size() == mesh->mNumVertices);

				mesh->mColors[0] = new aiColor4D[ mesh->mNumVertices ];
				::memcpy(mesh->mColors[0],&(*it2).colors[0],sizeof(aiColor4D)*mesh->mNumVertices);
			}

			// generate triangles
			ai_assert(0 == mesh->mNumVertices % 3);
			aiFace* fc = mesh->mFaces = new aiFace[ mesh->mNumFaces = mesh->mNumVertices/3 ];
			aiFace* const fcEnd = fc + mesh->mNumFaces;
			unsigned int n = 0;
			while (fc != fcEnd)
			{
				aiFace& f = *fc++;
				f.mIndices = new unsigned int[f.mNumIndices = 3];
				for (unsigned int m = 0; m < 3;++m)
					f.mIndices[m] = n++;
			}

			// generate a material for the mesh
			MaterialHelper* mat = new MaterialHelper();

			aiColor4D clr(1.0f,1.0f,1.0f,1.0f);
			if ("%default%" == (*it2).name) // a gray default material
			{
				clr.r = clr.g = clr.b = 0.6f;
			}
			else if ((*it2).name.length() > 0) // a texture
			{
				aiString s;
				s.Set((*it2).name);
				mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
			}
			mat->AddProperty<aiColor4D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
			*mats++ = mat;
		}
	}
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void DXFImporter::InternReadFile( const std::string& pFile, 
	aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));

	// Check whether we can read from the file
	if( file.get() == NULL) {
		throw DeadlyImportError( "Failed to open DXF file " + pFile + "");
	}

	// read the contents of the file in a buffer
	std::vector<char> buffer2;
	TextFileToBuffer(file.get(),buffer2);
	buffer = &buffer2[0];

	bRepeat = false;
	mDefaultLayer = NULL;

	// check whether this is a binaray DXF file - we can't read binary DXF files :-(
	if (!strncmp(AI_DXF_BINARY_IDENT,buffer,AI_DXF_BINARY_IDENT_LEN))
		throw DeadlyImportError("DXF: Binary files are not supported at the moment");

	// now get all lines of the file
	while (GetNextToken())	{

		if (2 == groupCode)	{

			// ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them
			if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS")) {
				if (!ParseEntities())
					break; 
				else bRepeat = true;
			}

			// other sections - skip them to make sure there will be no name conflicts
			else	{
				while ( GetNextToken())	{
					if (!::strcmp(cursor,"ENDSEC"))
						break;
				}
			}
		}
		// print comment strings
		else if (999 == groupCode)	{
			DefaultLogger::get()->info(std::string( cursor ));
		}
		else if (!groupCode && !::strcmp(cursor,"EOF"))
			break;
	}

	// find out how many valud layers we have
	for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end(); it != end;++it)	{
		if (!(*it).vPositions.empty())
			++pScene->mNumMeshes;
	}

	if (!pScene->mNumMeshes)
		throw DeadlyImportError("DXF: this file contains no 3d data");

	pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
	unsigned int m = 0;
	for (std::vector<LayerInfo>::const_iterator it = mLayers.begin(),end = mLayers.end();it != end;++it) {
		if ((*it).vPositions.empty()) {
			continue;
		}
		// generate the output mesh
		aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh();
		const std::vector<aiVector3D>& vPositions = (*it).vPositions;
		const std::vector<aiColor4D>& vColors = (*it).vColors;

		// check whether we need vertex colors here
		aiColor4D* clrOut = NULL;
		const aiColor4D* clr = NULL;
		for (std::vector<aiColor4D>::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end();it2 != end2; ++it2)	{
			
			if ((*it2).r == (*it2).r) /* qnan? */ {
				clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()];
				for (unsigned int i = 0; i < vPositions.size();++i)
					clrOut[i] = aiColor4D(0.6f,0.6f,0.6f,1.0f);

				clr = &vColors[0];
				break;
			}
		}

		pMesh->mNumFaces = (unsigned int)vPositions.size() / 4u;
		pMesh->mFaces = new aiFace[pMesh->mNumFaces];

		aiVector3D* vpOut = pMesh->mVertices = new aiVector3D[vPositions.size()];
		const aiVector3D* vp = &vPositions[0];

		for (unsigned int i = 0; i < pMesh->mNumFaces;++i)	{
			aiFace& face = pMesh->mFaces[i];

			// check whether we need four, three or two indices here
			if (vp[1] == vp[2])	{
				face.mNumIndices = 2;
			}
			else if (vp[3] == vp[2])	{
				 face.mNumIndices = 3;
			}
			else face.mNumIndices = 4;
			face.mIndices = new unsigned int[face.mNumIndices];

			for (unsigned int a = 0; a < face.mNumIndices;++a)	{
				*vpOut++ = vp[a];
				if (clr)	{
					if (is_not_qnan( clr[a].r )) {
						*clrOut = clr[a];
					}
					++clrOut;
				}
				face.mIndices[a] = pMesh->mNumVertices++;
			}
			vp += 4;
		}
	}

	// generate the output scene graph
	pScene->mRootNode = new aiNode();
	pScene->mRootNode->mName.Set("<DXF_ROOT>");

	if (1 == pScene->mNumMeshes)	{
		pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ];
		pScene->mRootNode->mMeshes[0] = 0;
	}
	else
	{
		pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ];
		for (m = 0; m < pScene->mRootNode->mNumChildren;++m)	{
			aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode();
			p->mName.length = ::strlen( mLayers[m].name );
			strcpy_s(p->mName.data, mLayers[m].name);

			p->mMeshes = new unsigned int[p->mNumMeshes = 1];
			p->mMeshes[0] = m;
			p->mParent = pScene->mRootNode;
		}
	}

	// generate a default material
	MaterialHelper* pcMat = new MaterialHelper();
	aiString s;
	s.Set(AI_DEFAULT_MATERIAL_NAME);
	pcMat->AddProperty(&s, AI_MATKEY_NAME);

	aiColor4D clrDiffuse(0.6f,0.6f,0.6f,1.0f);
	pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);

	clrDiffuse = aiColor4D(1.0f,1.0f,1.0f,1.0f);
	pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);

	clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f);
	pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);

	pScene->mNumMaterials = 1;
	pScene->mMaterials = new aiMaterial*[1];
	pScene->mMaterials[0] = pcMat;

	// flip winding order to be ccw
	FlipWindingOrderProcess flipper;
	flipper.Execute(pScene);

	// --- everything destructs automatically ---
}
Exemple #4
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void MD2Importer::InternReadFile( const std::string& pFile, 
	aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw new ImportErrorException( "Failed to open MD2 file " + pFile + "");

	// check whether the md3 file is large enough to contain
	// at least the file header
	fileSize = (unsigned int)file->FileSize();
	if( fileSize < sizeof(MD2::Header))
		throw new ImportErrorException( "MD2 File is too small");

	std::vector<uint8_t> mBuffer2(fileSize);
	file->Read(&mBuffer2[0], 1, fileSize);
	mBuffer = &mBuffer2[0];


	m_pcHeader = (BE_NCONST MD2::Header*)mBuffer;

#ifdef AI_BUILD_BIG_ENDIAN

	ByteSwap::Swap4(&m_pcHeader->frameSize);
	ByteSwap::Swap4(&m_pcHeader->magic);
	ByteSwap::Swap4(&m_pcHeader->numFrames);
	ByteSwap::Swap4(&m_pcHeader->numGlCommands);
	ByteSwap::Swap4(&m_pcHeader->numSkins);
	ByteSwap::Swap4(&m_pcHeader->numTexCoords);
	ByteSwap::Swap4(&m_pcHeader->numTriangles);
	ByteSwap::Swap4(&m_pcHeader->numVertices);
	ByteSwap::Swap4(&m_pcHeader->offsetEnd);
	ByteSwap::Swap4(&m_pcHeader->offsetFrames);
	ByteSwap::Swap4(&m_pcHeader->offsetGlCommands);
	ByteSwap::Swap4(&m_pcHeader->offsetSkins);
	ByteSwap::Swap4(&m_pcHeader->offsetTexCoords);
	ByteSwap::Swap4(&m_pcHeader->offsetTriangles);
	ByteSwap::Swap4(&m_pcHeader->skinHeight);
	ByteSwap::Swap4(&m_pcHeader->skinWidth);
	ByteSwap::Swap4(&m_pcHeader->version);

#endif

	ValidateHeader();

	// there won't be more than one mesh inside the file
	pScene->mNumMaterials = 1;
	pScene->mRootNode = new aiNode();
	pScene->mRootNode->mNumMeshes = 1;
	pScene->mRootNode->mMeshes = new unsigned int[1];
	pScene->mRootNode->mMeshes[0] = 0;
	pScene->mMaterials = new aiMaterial*[1];
	pScene->mMaterials[0] = new MaterialHelper();
	pScene->mNumMeshes = 1;
	pScene->mMeshes = new aiMesh*[1];

	aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
	pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;

	// navigate to the begin of the frame data
	BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
		m_pcHeader + m_pcHeader->offsetFrames);

	pcFrame += configFrameID;

	// navigate to the begin of the triangle data
	MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
		m_pcHeader + m_pcHeader->offsetTriangles);

	// navigate to the begin of the tex coords data
	BE_NCONST MD2::TexCoord* pcTexCoords = (BE_NCONST MD2::TexCoord*) ((uint8_t*)
		m_pcHeader + m_pcHeader->offsetTexCoords);

	// navigate to the begin of the vertex data
	BE_NCONST MD2::Vertex* pcVerts = (BE_NCONST MD2::Vertex*) (pcFrame->vertices);

#ifdef AI_BUILD_BIG_ENDIAN
	for (uint32_t i = 0; i< m_pcHeader->numTriangles; ++i)
	{
		for (unsigned int p = 0; p < 3;++p)
		{
			ByteSwap::Swap2(& pcTriangles[i].textureIndices[p]);
			ByteSwap::Swap2(& pcTriangles[i].vertexIndices[p]);
		}
	}
	for (uint32_t i = 0; i < m_pcHeader->offsetTexCoords;++i)
	{
		ByteSwap::Swap2(& pcTexCoords[i].s);
		ByteSwap::Swap2(& pcTexCoords[i].t);
	}
	ByteSwap::Swap4( & pcFrame->scale[0] );
	ByteSwap::Swap4( & pcFrame->scale[1] );
	ByteSwap::Swap4( & pcFrame->scale[2] );
	ByteSwap::Swap4( & pcFrame->translate[0] );
	ByteSwap::Swap4( & pcFrame->translate[1] );
	ByteSwap::Swap4( & pcFrame->translate[2] );
#endif

	pcMesh->mNumFaces = m_pcHeader->numTriangles;
	pcMesh->mFaces = new aiFace[m_pcHeader->numTriangles];

	// allocate output storage
	pcMesh->mNumVertices = (unsigned int)pcMesh->mNumFaces*3;
	pcMesh->mVertices = new aiVector3D[pcMesh->mNumVertices];
	pcMesh->mNormals = new aiVector3D[pcMesh->mNumVertices];

	// Not sure whether there are MD2 files without texture coordinates
	// NOTE: texture coordinates can be there without a texture,
	// but a texture can't be there without a valid UV channel
	MaterialHelper* pcHelper = (MaterialHelper*)pScene->mMaterials[0];
	const int iMode = (int)aiShadingMode_Gouraud;
	pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);

	if (m_pcHeader->numTexCoords && m_pcHeader->numSkins)
	{
		// navigate to the first texture associated with the mesh
		const MD2::Skin* pcSkins = (const MD2::Skin*) ((unsigned char*)m_pcHeader + 
			m_pcHeader->offsetSkins);

		aiColor3D clr;
		clr.b = clr.g = clr.r = 1.0f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);

		clr.b = clr.g = clr.r = 0.05f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);

		if (pcSkins->name[0])
		{
			aiString szString;
			const size_t iLen = ::strlen(pcSkins->name);
			::memcpy(szString.data,pcSkins->name,iLen);
			szString.data[iLen] = '\0';
			szString.length = iLen;

			pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
		}
		else{
			DefaultLogger::get()->warn("Texture file name has zero length. It will be skipped.");
		}
	}
	else	{
		// apply a default material
		aiColor3D clr;
		clr.b = clr.g = clr.r = 0.6f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);

		clr.b = clr.g = clr.r = 0.05f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);

		aiString szName;
		szName.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME);
		pcHelper->AddProperty(&szName,AI_MATKEY_NAME);

		aiString sz;

		// TODO: Try to guess the name of the texture file from the model file name

		sz.Set("$texture_dummy.bmp");
		pcHelper->AddProperty(&sz,AI_MATKEY_TEXTURE_DIFFUSE(0));
	}


	// now read all triangles of the first frame, apply scaling and translation
	unsigned int iCurrent = 0;

	float fDivisorU = 1.0f,fDivisorV = 1.0f;
	if (m_pcHeader->numTexCoords)	{
		// allocate storage for texture coordinates, too
		pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
		pcMesh->mNumUVComponents[0] = 2;

		// check whether the skin width or height are zero (this would
		// cause a division through zero)
		if (!m_pcHeader->skinWidth)	{
			DefaultLogger::get()->error("MD2: No valid skin width given");
		}
		else fDivisorU = (float)m_pcHeader->skinWidth;
		if (!m_pcHeader->skinHeight){
			DefaultLogger::get()->error("MD2: No valid skin height given");
		}
		else fDivisorV = (float)m_pcHeader->skinHeight;
	}

	for (unsigned int i = 0; i < (unsigned int)m_pcHeader->numTriangles;++i)	{
		// Allocate the face
		pScene->mMeshes[0]->mFaces[i].mIndices = new unsigned int[3];
		pScene->mMeshes[0]->mFaces[i].mNumIndices = 3;

		// copy texture coordinates
		// check whether they are different from the previous value at this index.
		// In this case, create a full separate set of vertices/normals/texcoords
		for (unsigned int c = 0; c < 3;++c,++iCurrent)	{

			// validate vertex indices
			register unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
			if (iIndex >= m_pcHeader->numVertices)	{
				DefaultLogger::get()->error("MD2: Vertex index is outside the allowed range");
				iIndex = m_pcHeader->numVertices-1;
			}

			// read x,y, and z component of the vertex
			aiVector3D& vec = pcMesh->mVertices[iCurrent];

			vec.x = (float)pcVerts[iIndex].vertex[0] * pcFrame->scale[0];
			vec.x += pcFrame->translate[0];

			vec.y = (float)pcVerts[iIndex].vertex[1] * pcFrame->scale[1];
			vec.y += pcFrame->translate[1];

			vec.z = (float)pcVerts[iIndex].vertex[2] * pcFrame->scale[2];
			vec.z += pcFrame->translate[2];

			// read the normal vector from the precalculated normal table
			aiVector3D& vNormal = pcMesh->mNormals[iCurrent];
			LookupNormalIndex(pcVerts[iIndex].lightNormalIndex,vNormal);

			// flip z and y to become right-handed
			std::swap((float&)vNormal.z,(float&)vNormal.y);
			std::swap((float&)vec.z,(float&)vec.y);

			if (m_pcHeader->numTexCoords)	{
				// validate texture coordinates
				iIndex = pcTriangles[i].textureIndices[c];
				if (iIndex >= m_pcHeader->numTexCoords)	{
					DefaultLogger::get()->error("MD2: UV index is outside the allowed range");
					iIndex = m_pcHeader->numTexCoords-1;
				}

				aiVector3D& pcOut = pcMesh->mTextureCoords[0][iCurrent];

				// the texture coordinates are absolute values but we
				// need relative values between 0 and 1
				pcOut.x = pcTexCoords[iIndex].s / fDivisorU;
				pcOut.y = 1.f-pcTexCoords[iIndex].t / fDivisorV;
			}
			pScene->mMeshes[0]->mFaces[i].mIndices[c] = iCurrent;
		}
	}
}
Exemple #5
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void MDCImporter::InternReadFile( 
	const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw DeadlyImportError( "Failed to open MDC file " + pFile + ".");

	// check whether the mdc file is large enough to contain the file header
	fileSize = (unsigned int)file->FileSize();
	if( fileSize < sizeof(MDC::Header))
		throw DeadlyImportError( "MDC File is too small.");

	std::vector<unsigned char> mBuffer2(fileSize);
	file->Read( &mBuffer2[0], 1, fileSize);
	mBuffer = &mBuffer2[0];

	// validate the file header
	this->pcHeader = (BE_NCONST MDC::Header*)this->mBuffer;
	this->ValidateHeader();

	std::vector<std::string> aszShaders;

	// get a pointer to the frame we want to read
	BE_NCONST MDC::Frame* pcFrame = (BE_NCONST MDC::Frame*)(this->mBuffer+
		this->pcHeader->ulOffsetBorderFrames);

	// no need to swap the other members, we won't need them
	pcFrame += configFrameID;
	AI_SWAP4( pcFrame->localOrigin[0] );
	AI_SWAP4( pcFrame->localOrigin[1] );
	AI_SWAP4( pcFrame->localOrigin[2] );

	// get the number of valid surfaces
	BE_NCONST MDC::Surface* pcSurface, *pcSurface2;
	pcSurface = pcSurface2 = (BE_NCONST MDC::Surface*)(mBuffer + pcHeader->ulOffsetSurfaces);
	unsigned int iNumShaders = 0;
	for (unsigned int i = 0; i < pcHeader->ulNumSurfaces;++i)
	{
		// validate the surface header
		this->ValidateSurfaceHeader(pcSurface2);

		if (pcSurface2->ulNumVertices && pcSurface2->ulNumTriangles)++pScene->mNumMeshes;
		iNumShaders += pcSurface2->ulNumShaders;
		pcSurface2 = (BE_NCONST MDC::Surface*)((int8_t*)pcSurface2 + pcSurface2->ulOffsetEnd);
	}
	aszShaders.reserve(iNumShaders);
	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];

	// necessary that we don't crash if an exception occurs
	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
		pScene->mMeshes[i] = NULL;

	// now read all surfaces
	unsigned int iDefaultMatIndex = 0xffffffff;
	for (unsigned int i = 0, iNum = 0; i < pcHeader->ulNumSurfaces;++i)
	{
		if (!pcSurface->ulNumVertices || !pcSurface->ulNumTriangles)continue;
		aiMesh* pcMesh = pScene->mMeshes[iNum++] = new aiMesh();

		pcMesh->mNumFaces = pcSurface->ulNumTriangles;
		pcMesh->mNumVertices = pcMesh->mNumFaces * 3;

		// store the name of the surface for use as node name.
		// FIX: make sure there is a 0 termination
		const_cast<char&>(pcSurface->ucName[AI_MDC_MAXQPATH-1]) = '\0';
		pcMesh->mTextureCoords[3] = (aiVector3D*)pcSurface->ucName;

		// go to the first shader in the file. ignore the others.
		if (pcSurface->ulNumShaders)
		{
			const MDC::Shader* pcShader = (const MDC::Shader*)((int8_t*)pcSurface + pcSurface->ulOffsetShaders);
			pcMesh->mMaterialIndex = (unsigned int)aszShaders.size();
			
			// create a new shader
			aszShaders.push_back(std::string( pcShader->ucName, std::min(
				::strlen(pcShader->ucName),sizeof(pcShader->ucName)) ));
		}
		// need to create a default material
		else if (0xffffffff == iDefaultMatIndex)
		{
			pcMesh->mMaterialIndex = iDefaultMatIndex = (unsigned int)aszShaders.size();
			aszShaders.push_back(std::string());
		}
		// otherwise assign a reference to the default material
		else pcMesh->mMaterialIndex = iDefaultMatIndex;

		// allocate output storage for the mesh
		aiVector3D* pcVertCur	= pcMesh->mVertices			= new aiVector3D[pcMesh->mNumVertices];
		aiVector3D* pcNorCur	= pcMesh->mNormals			= new aiVector3D[pcMesh->mNumVertices];
		aiVector3D* pcUVCur		= pcMesh->mTextureCoords[0] = new aiVector3D[pcMesh->mNumVertices];
		aiFace* pcFaceCur		= pcMesh->mFaces			= new aiFace[pcMesh->mNumFaces];

		// create all vertices/faces
		BE_NCONST MDC::Triangle* pcTriangle = (BE_NCONST MDC::Triangle*)
			((int8_t*)pcSurface+pcSurface->ulOffsetTriangles);

		BE_NCONST MDC::TexturCoord* const pcUVs = (BE_NCONST MDC::TexturCoord*)
			((int8_t*)pcSurface+pcSurface->ulOffsetTexCoords);

		// get a pointer to the uncompressed vertices
		int16_t iOfs = *((int16_t*) ((int8_t*) pcSurface +
			pcSurface->ulOffsetFrameBaseFrames) +  this->configFrameID);

		AI_SWAP2(iOfs);

		BE_NCONST MDC::BaseVertex* const pcVerts = (BE_NCONST MDC::BaseVertex*)
			((int8_t*)pcSurface+pcSurface->ulOffsetBaseVerts) +
			((int)iOfs * pcSurface->ulNumVertices * 4);

		// do the main swapping stuff ...
#if (defined AI_BUILD_BIG_ENDIAN)

		// swap all triangles
		for (unsigned int i = 0; i < pcSurface->ulNumTriangles;++i)
		{
			AI_SWAP4( pcTriangle[i].aiIndices[0] );
			AI_SWAP4( pcTriangle[i].aiIndices[1] );
			AI_SWAP4( pcTriangle[i].aiIndices[2] );
		}

		// swap all vertices
		for (unsigned int i = 0; i < pcSurface->ulNumVertices*pcSurface->ulNumBaseFrames;++i)
		{
			AI_SWAP2( pcVerts->normal );
			AI_SWAP2( pcVerts->x );
			AI_SWAP2( pcVerts->y );
			AI_SWAP2( pcVerts->z );
		}

		// swap all texture coordinates
		for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i)
		{
			AI_SWAP4( pcUVs->v );
			AI_SWAP4( pcUVs->v );
		}

#endif

		const MDC::CompressedVertex* pcCVerts = NULL;
		int16_t* mdcCompVert = NULL;

		// access compressed frames for large frame numbers, but never for the first
		if( this->configFrameID && pcSurface->ulNumCompFrames > 0 )
		{
			mdcCompVert = (int16_t*) ((int8_t*)pcSurface+pcSurface->ulOffsetFrameCompFrames) + this->configFrameID;
			AI_SWAP2P(mdcCompVert);
			if( *mdcCompVert >= 0 )
			{
				pcCVerts = (const MDC::CompressedVertex*)((int8_t*)pcSurface +
					pcSurface->ulOffsetCompVerts) + *mdcCompVert * pcSurface->ulNumVertices;
			}
			else mdcCompVert = NULL;
		}

		// copy all faces
		for (unsigned int iFace = 0; iFace < pcSurface->ulNumTriangles;++iFace,
			++pcTriangle,++pcFaceCur)
		{
			const unsigned int iOutIndex = iFace*3;
			pcFaceCur->mNumIndices = 3;
			pcFaceCur->mIndices = new unsigned int[3];

			for (unsigned int iIndex = 0; iIndex < 3;++iIndex,
				++pcVertCur,++pcUVCur,++pcNorCur)
			{
				uint32_t quak = pcTriangle->aiIndices[iIndex];
				if (quak >= pcSurface->ulNumVertices)
				{
					DefaultLogger::get()->error("MDC vertex index is out of range");
					quak = pcSurface->ulNumVertices-1;
				}

				// compressed vertices?
				if (mdcCompVert)
				{
					MDC::BuildVertex(*pcFrame,pcVerts[quak],pcCVerts[quak],
						*pcVertCur,*pcNorCur);
				}
				else
				{
					// copy position
					pcVertCur->x = pcVerts[quak].x * AI_MDC_BASE_SCALING;
					pcVertCur->y = pcVerts[quak].y * AI_MDC_BASE_SCALING;
					pcVertCur->z = pcVerts[quak].z * AI_MDC_BASE_SCALING;

					// copy normals
					MD3::LatLngNormalToVec3( pcVerts[quak].normal, &pcNorCur->x );

					// copy texture coordinates
					pcUVCur->x = pcUVs[quak].u;
					pcUVCur->y = 1.0f-pcUVs[quak].v; // DX to OGL
				}
				pcVertCur->x += pcFrame->localOrigin[0] ;
				pcVertCur->y += pcFrame->localOrigin[1] ;
				pcVertCur->z += pcFrame->localOrigin[2] ;
			}

			// swap the face order - DX to OGL
			pcFaceCur->mIndices[0] = iOutIndex + 2;
			pcFaceCur->mIndices[1] = iOutIndex + 1;
			pcFaceCur->mIndices[2] = iOutIndex + 0;
		}

		pcSurface = (BE_NCONST MDC::Surface*)((int8_t*)pcSurface + pcSurface->ulOffsetEnd);
	}

	// create a flat node graph with a root node and one child for each surface
	if (!pScene->mNumMeshes)
		throw DeadlyImportError( "Invalid MDC file: File contains no valid mesh");
	else if (1 == pScene->mNumMeshes)
	{
		pScene->mRootNode = new aiNode();
		pScene->mRootNode->mName.Set(std::string((const char*)pScene->mMeshes[0]->mTextureCoords[3]));
		pScene->mRootNode->mNumMeshes = 1;
		pScene->mRootNode->mMeshes = new unsigned int[1];
		pScene->mRootNode->mMeshes[0] = 0;
	}
	else
	{
		pScene->mRootNode = new aiNode();
		pScene->mRootNode->mNumChildren = pScene->mNumMeshes;
		pScene->mRootNode->mChildren = new aiNode*[pScene->mNumMeshes];
		pScene->mRootNode->mName.Set("<root>");
		for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
		{
			aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
			pcNode->mParent = pScene->mRootNode;
			pcNode->mName.Set(std::string((const char*)pScene->mMeshes[i]->mTextureCoords[3]));
			pcNode->mNumMeshes = 1;
			pcNode->mMeshes = new unsigned int[1];
			pcNode->mMeshes[0] = i;
		}
	}

	// make sure we invalidate the pointer to the mesh name
	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
		pScene->mMeshes[i]->mTextureCoords[3] = NULL;

	// create materials
	pScene->mNumMaterials = (unsigned int)aszShaders.size();
	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
	for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
	{
		MaterialHelper* pcMat = new MaterialHelper();
		pScene->mMaterials[i] = pcMat;

		const std::string& name = aszShaders[i];

		int iMode = (int)aiShadingMode_Gouraud;
		pcMat->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);

		// add a small ambient color value - RtCW seems to have one
		aiColor3D clr;
		clr.b = clr.g = clr.r = 0.05f;
		pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);

		if (name.length())clr.b = clr.g = clr.r = 1.0f;
		else clr.b = clr.g = clr.r = 0.6f;

		pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
		pcMat->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);

		if (name.length())
		{
			aiString path;
			path.Set(name);
			pcMat->AddProperty(&path,AI_MATKEY_TEXTURE_DIFFUSE(0));
		}
	}
}
Exemple #6
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void IRRMeshImporter::InternReadFile( const std::string& pFile, 
	aiScene* pScene, IOSystem* pIOHandler)
{
	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw DeadlyImportError( "Failed to open IRRMESH file " + pFile + "");

	// Construct the irrXML parser
	CIrrXML_IOStreamReader st(file.get());
	reader = createIrrXMLReader((IFileReadCallBack*) &st);

	// final data
	std::vector<aiMaterial*> materials;
	std::vector<aiMesh*>     meshes;
	materials.reserve (5);
	meshes.reserve    (5);

	// temporary data - current mesh buffer
	aiMaterial* curMat	= NULL;
	aiMesh* curMesh		= NULL;
	unsigned int curMatFlags;

	std::vector<aiVector3D> curVertices,curNormals,curTangents,curBitangents;
	std::vector<aiColor4D>  curColors;
	std::vector<aiVector3D> curUVs,curUV2s;

	// some temporary variables
	int textMeaning = 0;
	int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
	bool useColors = false;

	// Parse the XML file
	while (reader->read())	{
		switch (reader->getNodeType())	{
		case EXN_ELEMENT:
			
			if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh))	{
				// end of previous buffer. A material and a mesh should be there
				if ( !curMat || !curMesh)	{
					DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material");
					delete curMat;
					delete curMesh;
				}
				else	{
					materials.push_back(curMat); 
					meshes.push_back(curMesh);  
				}
				curMat  = NULL;
				curMesh = NULL;

				curVertices.clear();
				curColors.clear();
				curNormals.clear();
				curUV2s.clear();
				curUVs.clear();
				curTangents.clear();
				curBitangents.clear();
			}
			

			if (!ASSIMP_stricmp(reader->getNodeName(),"material"))	{
				if (curMat)	{
					DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please");
					delete curMat;curMat = NULL;
				}
				curMat = ParseMaterial(curMatFlags);
			}
			/* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices"))
			{
				int num = reader->getAttributeValueAsInt("vertexCount");

				if (!num)	{
					// This is possible ... remove the mesh from the list and skip further reading
					DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices");

					delete curMat;curMat = NULL;

					curMesh = NULL;
					textMeaning = 0;
					continue;
				}

				curVertices.reserve (num);
				curNormals.reserve  (num);
				curColors.reserve   (num);
				curUVs.reserve      (num);

				// Determine the file format
				const char* t = reader->getAttributeValueSafe("type");
				if (!ASSIMP_stricmp("2tcoords", t))	{
					curUV2s.reserve (num);
					vertexFormat = 1;

					if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE)	{
						// *********************************************************
						// We have a second texture! So use this UV channel
						// for it. The 2nd texture can be either a normal
						// texture (solid_2layer or lightmap_xxx) or a normal 
						// map (normal_..., parallax_...)
						// *********************************************************
						int idx = 1;
						MaterialHelper* mat = ( MaterialHelper* ) curMat;

						if (curMatFlags & AI_IRRMESH_MAT_lightmap){
							mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_LIGHTMAP(0));
						}
						else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid){
							mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_NORMALS(0));
						}
						else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
							mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(1));
						}
					}
				}
				else if (!ASSIMP_stricmp("tangents", t))	{
					curTangents.reserve (num);
					curBitangents.reserve (num);
					vertexFormat = 2;
				}
				else if (ASSIMP_stricmp("standard", t))	{
					delete curMat;
					DefaultLogger::get()->warn("IRRMESH: Unknown vertex format");
				}
				else vertexFormat = 0;
				textMeaning = 1;
			}
			else if (!ASSIMP_stricmp(reader->getNodeName(),"indices"))	{
				if (curVertices.empty() && curMat)	{
					delete curMat;
					throw DeadlyImportError("IRRMESH: indices must come after vertices");
				}

				textMeaning = 2;

				// start a new mesh
				curMesh = new aiMesh();

				// allocate storage for all faces
				curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
				if (!curMesh->mNumVertices)	{
					// This is possible ... remove the mesh from the list and skip further reading
					DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices");

					// mesh - away
					delete curMesh; curMesh = NULL;

					// material - away
					delete curMat;curMat = NULL;

					textMeaning = 0;
					continue;
				}

				if (curMesh->mNumVertices % 3)	{
					DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3");
				}

				curMesh->mNumFaces = curMesh->mNumVertices / 3;
				curMesh->mFaces = new aiFace[curMesh->mNumFaces];

				// setup some members
				curMesh->mMaterialIndex = (unsigned int)materials.size();
				curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;

				// allocate storage for all vertices
				curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];

				if (curNormals.size() == curVertices.size())	{
					curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
				}
				if (curTangents.size() == curVertices.size())	{
					curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
				}
				if (curBitangents.size() == curVertices.size())	{
					curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
				}
				if (curColors.size() == curVertices.size() && useColors)	{
					curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
				}
				if (curUVs.size() == curVertices.size())	{
					curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
				}
				if (curUV2s.size() == curVertices.size())	{
					curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
				}
			}
			break;

		case EXN_TEXT:
			{
			const char* sz = reader->getNodeData();
			if (textMeaning == 1)	{
				textMeaning = 0;

				// read vertices
				do	{
					SkipSpacesAndLineEnd(&sz);
					aiVector3D temp;aiColor4D c;

					// Read the vertex position
					sz = fast_atof_move(sz,(float&)temp.x);
					SkipSpaces(&sz);

					sz = fast_atof_move(sz,(float&)temp.y);
					SkipSpaces(&sz);

					sz = fast_atof_move(sz,(float&)temp.z);
					SkipSpaces(&sz);
					curVertices.push_back(temp);

					// Read the vertex normals
					sz = fast_atof_move(sz,(float&)temp.x);
					SkipSpaces(&sz);

					sz = fast_atof_move(sz,(float&)temp.y);
					SkipSpaces(&sz);

					sz = fast_atof_move(sz,(float&)temp.z);
					SkipSpaces(&sz);
					curNormals.push_back(temp);

					// read the vertex colors
					uint32_t clr = strtol16(sz,&sz);	
					ColorFromARGBPacked(clr,c);

					if (!curColors.empty() && c != *(curColors.end()-1))
						useColors = true;

					curColors.push_back(c);
					SkipSpaces(&sz);


					// read the first UV coordinate set
					sz = fast_atof_move(sz,(float&)temp.x);
					SkipSpaces(&sz);

					sz = fast_atof_move(sz,(float&)temp.y);
					SkipSpaces(&sz);
					temp.z = 0.f;
					temp.y = 1.f - temp.y;  // DX to OGL
					curUVs.push_back(temp);

					// read the (optional) second UV coordinate set
					if (vertexFormat == 1)	{
						sz = fast_atof_move(sz,(float&)temp.x);
						SkipSpaces(&sz);

						sz = fast_atof_move(sz,(float&)temp.y);
						temp.y = 1.f - temp.y; // DX to OGL
						curUV2s.push_back(temp);
					}
					// read optional tangent and bitangent vectors
					else if (vertexFormat == 2)	{
						// tangents
						sz = fast_atof_move(sz,(float&)temp.x);
						SkipSpaces(&sz);

						sz = fast_atof_move(sz,(float&)temp.z);
						SkipSpaces(&sz);

						sz = fast_atof_move(sz,(float&)temp.y);
						SkipSpaces(&sz);
						temp.y *= -1.0f;
						curTangents.push_back(temp);

						// bitangents
						sz = fast_atof_move(sz,(float&)temp.x);
						SkipSpaces(&sz);

						sz = fast_atof_move(sz,(float&)temp.z);
						SkipSpaces(&sz);

						sz = fast_atof_move(sz,(float&)temp.y);
						SkipSpaces(&sz);
						temp.y *= -1.0f;
						curBitangents.push_back(temp);
					}
				}

				/* IMPORTANT: We assume that each vertex is specified in one
				   line. So we can skip the rest of the line - unknown vertex
				   elements are ignored.
				 */

				while (SkipLine(&sz));
			}
			else if (textMeaning == 2)	{
				textMeaning = 0;

				// read indices
				aiFace* curFace = curMesh->mFaces;
				aiFace* const faceEnd = curMesh->mFaces  + curMesh->mNumFaces;

				aiVector3D* pcV  = curMesh->mVertices;
				aiVector3D* pcN  = curMesh->mNormals;
				aiVector3D* pcT  = curMesh->mTangents;
				aiVector3D* pcB  = curMesh->mBitangents;
				aiColor4D* pcC0  = curMesh->mColors[0];
				aiVector3D* pcT0 = curMesh->mTextureCoords[0];
				aiVector3D* pcT1 = curMesh->mTextureCoords[1];

				unsigned int curIdx = 0;
				unsigned int total = 0;
				while(SkipSpacesAndLineEnd(&sz))	{
					if (curFace >= faceEnd)	{
						DefaultLogger::get()->error("IRRMESH: Too many indices");
						break;
					}
					if (!curIdx)	{
						curFace->mNumIndices = 3;
						curFace->mIndices = new unsigned int[3];
					}

					unsigned int idx = strtol10(sz,&sz);
					if (idx >= curVertices.size())	{
						DefaultLogger::get()->error("IRRMESH: Index out of range");
						idx = 0;
					}

					curFace->mIndices[curIdx] = total++;

					*pcV++ = curVertices[idx];
					if (pcN)*pcN++ = curNormals[idx];
					if (pcT)*pcT++ = curTangents[idx];
					if (pcB)*pcB++ = curBitangents[idx];
					if (pcC0)*pcC0++ = curColors[idx];
					if (pcT0)*pcT0++ = curUVs[idx];
					if (pcT1)*pcT1++ = curUV2s[idx];

					if (++curIdx == 3)	{
						++curFace;
						curIdx = 0;
					}
				}

				if (curFace != faceEnd)
					DefaultLogger::get()->error("IRRMESH: Not enough indices");

				// Finish processing the mesh - do some small material workarounds
				if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors)	{
					// Take the opacity value of the current material
					// from the common vertex color alpha
					MaterialHelper* mat = (MaterialHelper*)curMat;
					mat->AddProperty(&curColors[0].a,1,AI_MATKEY_OPACITY);
				}
			}}
			break;

			default:

				// GCC complains here ...
				break;

		};
	}

	// End of the last buffer. A material and a mesh should be there
	if (curMat || curMesh)	{
		if ( !curMat || !curMesh)	{
			DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material");
			delete curMat;
			delete curMesh;
		}
		else	{
			materials.push_back(curMat); 
			meshes.push_back(curMesh);  
		}
	}

	if (materials.empty())
		throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");


	// now generate the output scene
	pScene->mNumMeshes = (unsigned int)meshes.size();
	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)	{
		pScene->mMeshes[i] = meshes[i];

		// clean this value ...
		pScene->mMeshes[i]->mNumUVComponents[3] = 0;
	}

	pScene->mNumMaterials = (unsigned int)materials.size();
	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
	::memcpy(pScene->mMaterials,&materials[0],sizeof(void*)*pScene->mNumMaterials);

	pScene->mRootNode = new aiNode();
	pScene->mRootNode->mName.Set("<IRRMesh>");
	pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
	pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];

	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
		pScene->mRootNode->mMeshes[i] = i;

	// clean up and return
	delete reader;
	AI_DEBUG_INVALIDATE_PTR(reader);
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void UnrealImporter::InternReadFile( const std::string& pFile,
    aiScene* pScene, IOSystem* pIOHandler)
{
    // For any of the 3 files being passed get the three correct paths
    // First of all, determine file extension
    std::string::size_type pos = pFile.find_last_of('.');
    std::string extension = GetExtension(pFile);

    std::string d_path,a_path,uc_path;
    if (extension == "3d")  {
        // jjjj_d.3d
        // jjjj_a.3d
        pos = pFile.find_last_of('_');
        if (std::string::npos == pos) {
            throw DeadlyImportError("UNREAL: Unexpected naming scheme");
        }
        extension = pFile.substr(0,pos);
    }
    else {
        extension = pFile.substr(0,pos);
    }

    // build proper paths
    d_path  = extension+"_d.3d";
    a_path  = extension+"_a.3d";
    uc_path = extension+".uc";

    DefaultLogger::get()->debug("UNREAL: data file is " + d_path);
    DefaultLogger::get()->debug("UNREAL: aniv file is " + a_path);
    DefaultLogger::get()->debug("UNREAL: uc file is "   + uc_path);

    // and open the files ... we can't live without them
    IOStream* p = pIOHandler->Open(d_path);
    if (!p)
        throw DeadlyImportError("UNREAL: Unable to open _d file");
    StreamReaderLE d_reader(pIOHandler->Open(d_path));

    const uint16_t numTris = d_reader.GetI2();
    const uint16_t numVert = d_reader.GetI2();
    d_reader.IncPtr(44);
    if (!numTris || numVert < 3)
        throw DeadlyImportError("UNREAL: Invalid number of vertices/triangles");

    // maximum texture index
    unsigned int maxTexIdx = 0;

    // collect triangles
    std::vector<Unreal::Triangle> triangles(numTris);
    for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
        Unreal::Triangle& tri = *it;

        for (unsigned int i = 0; i < 3;++i) {

            tri.mVertex[i] = d_reader.GetI2();
            if (tri.mVertex[i] >= numTris) {
                DefaultLogger::get()->warn("UNREAL: vertex index out of range");
                tri.mVertex[i] = 0;
            }
        }
        tri.mType = d_reader.GetI1();

        // handle mesh flagss?
        if (configHandleFlags)
            tri.mType = Unreal::MF_NORMAL_OS;
        else {
            // ignore MOD and MASKED for the moment, treat them as two-sided
            if (tri.mType == Unreal::MF_NORMAL_MOD_TS || tri.mType == Unreal::MF_NORMAL_MASKED_TS)
                tri.mType = Unreal::MF_NORMAL_TS;
        }
        d_reader.IncPtr(1);

        for (unsigned int i = 0; i < 3;++i)
            for (unsigned int i2 = 0; i2 < 2;++i2)
                tri.mTex[i][i2] = d_reader.GetI1();

        tri.mTextureNum = d_reader.GetI1();
        maxTexIdx = std::max(maxTexIdx,(unsigned int)tri.mTextureNum);
        d_reader.IncPtr(1);
    }

    p = pIOHandler->Open(a_path);
    if (!p)
        throw DeadlyImportError("UNREAL: Unable to open _a file");
    StreamReaderLE a_reader(pIOHandler->Open(a_path));

    // read number of frames
    const uint32_t numFrames = a_reader.GetI2();
    if (configFrameID >= numFrames)
        throw DeadlyImportError("UNREAL: The requested frame does not exist");

    uint32_t st = a_reader.GetI2();
    if (st != numVert*4u)
        throw DeadlyImportError("UNREAL: Unexpected aniv file length");

    // skip to our frame
    a_reader.IncPtr(configFrameID *numVert*4);

    // collect vertices
    std::vector<aiVector3D> vertices(numVert);
    for (std::vector<aiVector3D>::iterator it = vertices.begin(), end = vertices.end(); it != end; ++it) {
        int32_t val = a_reader.GetI4();
        Unreal::DecompressVertex(*it,val);
    }

    // list of textures.
    std::vector< std::pair<unsigned int, std::string> > textures;

    // allocate the output scene
    aiNode* nd = pScene->mRootNode = new aiNode();
    nd->mName.Set("<UnrealRoot>");

    // we can live without the uc file if necessary
    boost::scoped_ptr<IOStream> pb (pIOHandler->Open(uc_path));
    if (pb.get()) {

        std::vector<char> _data;
        TextFileToBuffer(pb.get(),_data);
        const char* data = &_data[0];

        std::vector< std::pair< std::string,std::string > > tempTextures;

        // do a quick search in the UC file for some known, usually texture-related, tags
        for (;*data;++data) {
            if (TokenMatchI(data,"#exec",5)) {
                SkipSpacesAndLineEnd(&data);

                // #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...]
                if (TokenMatchI(data,"TEXTURE",7)) {
                    SkipSpacesAndLineEnd(&data);

                    if (TokenMatchI(data,"IMPORT",6)) {
                        tempTextures.push_back(std::pair< std::string,std::string >());
                        std::pair< std::string,std::string >& me = tempTextures.back();
                        for (;!IsLineEnd(*data);++data) {
                            if (!::ASSIMP_strincmp(data,"NAME=",5)) {
                                const char *d = data+=5;
                                for (;!IsSpaceOrNewLine(*data);++data) {};
                                me.first = std::string(d,(size_t)(data-d));
                            }
                            else if (!::ASSIMP_strincmp(data,"FILE=",5)) {
                                const char *d = data+=5;
                                for (;!IsSpaceOrNewLine(*data);++data) {};
                                me.second = std::string(d,(size_t)(data-d));
                            }
                        }
                        if (!me.first.length() || !me.second.length())
                            tempTextures.pop_back();
                    }
                }
                // #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1
                // #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2
                else if (TokenMatchI(data,"MESHMAP",7)) {
                    SkipSpacesAndLineEnd(&data);

                    if (TokenMatchI(data,"SETTEXTURE",10)) {

                        textures.push_back(std::pair<unsigned int, std::string>());
                        std::pair<unsigned int, std::string>& me = textures.back();

                        for (;!IsLineEnd(*data);++data) {
                            if (!::ASSIMP_strincmp(data,"NUM=",4)) {
                                data += 4;
                                me.first = strtol10(data,&data);
                            }
                            else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) {
                                data += 8;
                                const char *d = data;
                                for (;!IsSpaceOrNewLine(*data);++data) {};
                                me.second = std::string(d,(size_t)(data-d));

                                // try to find matching path names, doesn't care if we don't find them
                                for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin();
                                     it != tempTextures.end(); ++it) {
                                    if ((*it).first == me.second) {
                                        me.second = (*it).second;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else if (TokenMatchI(data,"SCALE",5)) {

                        for (;!IsLineEnd(*data);++data) {
                            if (data[0] == 'X' && data[1] == '=') {
                                data = fast_atof_move(data+2,(float&)nd->mTransformation.a1);
                            }
                            else if (data[0] == 'Y' && data[1] == '=') {
                                data = fast_atof_move(data+2,(float&)nd->mTransformation.b2);
                            }
                            else if (data[0] == 'Z' && data[1] == '=') {
                                data = fast_atof_move(data+2,(float&)nd->mTransformation.c3);
                            }
                        }
                    }
                }
            }
        }
    }
    else {
        DefaultLogger::get()->error("Unable to open .uc file");
    }

    std::vector<Unreal::TempMat> materials;
    materials.reserve(textures.size()*2+5);

    // find out how many output meshes and materials we'll have and build material indices
    for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
        Unreal::Triangle& tri = *it;
        Unreal::TempMat mat(tri);
        std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);
        if (nt == materials.end()) {
            // add material
            tri.matIndex = materials.size();
            mat.numFaces = 1;
            materials.push_back(mat);

            ++pScene->mNumMeshes;
        }
        else {
            tri.matIndex = static_cast<unsigned int>(nt-materials.begin());
            ++nt->numFaces;
        }
    }

    if (!pScene->mNumMeshes) {
        throw DeadlyImportError("UNREAL: Unable to find valid mesh data");
    }

    // allocate meshes and bind them to the node graph
    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];

    nd->mNumMeshes  = pScene->mNumMeshes;
    nd->mMeshes = new unsigned int[nd->mNumMeshes];
    for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
        aiMesh* m = pScene->mMeshes[i] =  new aiMesh();
        m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;

        const unsigned int num = materials[i].numFaces;
        m->mFaces            = new aiFace     [num];
        m->mVertices         = new aiVector3D [num*3];
        m->mTextureCoords[0] = new aiVector3D [num*3];

        nd->mMeshes[i] = i;

        // create materials, too
        MaterialHelper* mat = new MaterialHelper();
        pScene->mMaterials[i] = mat;

        // all white by default - texture rulez
        aiColor3D color(1.f,1.f,1.f);

        aiString s;
        ::sprintf(s.data,"mat%i_tx%i_",i,materials[i].tex);

        // set the two-sided flag
        if (materials[i].type == Unreal::MF_NORMAL_TS) {
            const int twosided = 1;
            mat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED);
            ::strcat(s.data,"ts_");
        }
        else ::strcat(s.data,"os_");

        // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us
        if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) {
            const float opac = 0.9f;
            mat->AddProperty(&opac,1,AI_MATKEY_OPACITY);
            ::strcat(s.data,"tran_");
        }
        else ::strcat(s.data,"opaq_");

        // a special name for the weapon attachment point
        if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) {
            s.length = ::sprintf(s.data,"$WeaponTag$");
            color = aiColor3D(0.f,0.f,0.f);
        }

        // set color and name
        mat->AddProperty(&color,1,AI_MATKEY_COLOR_DIFFUSE);
        s.length = ::strlen(s.data);
        mat->AddProperty(&s,AI_MATKEY_NAME);

        // set texture, if any
        const unsigned int tex = materials[i].tex;
        for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin();it != textures.end();++it) {
            if ((*it).first == tex) {
                s.Set((*it).second);
                mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
                break;
            }
        }
    }

    // fill them.
    for (std::vector<Unreal::Triangle>::iterator it = triangles.begin(), end = triangles.end();it != end; ++it) {
        Unreal::Triangle& tri = *it;
        Unreal::TempMat mat(tri);
        std::vector<Unreal::TempMat>::iterator nt = std::find(materials.begin(),materials.end(),mat);

        aiMesh* mesh = pScene->mMeshes[nt-materials.begin()];
        aiFace& f    = mesh->mFaces[mesh->mNumFaces++];
        f.mIndices   = new unsigned int[f.mNumIndices = 3];

        for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) {
            f.mIndices[i] = mesh->mNumVertices;

            mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ];
            mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f);
        }
    }

    // convert to RH
    MakeLeftHandedProcess hero;
    hero.Execute(pScene);

    FlipWindingOrderProcess flipper;
    flipper.Execute(pScene);
}
Exemple #8
0
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. 
void MD3Importer::InternReadFile( const std::string& pFile, 
	aiScene* pScene, IOSystem* pIOHandler)
{
	mFile = pFile;
	mScene = pScene;
	mIOHandler = pIOHandler;

	// get base path and file name
	// todo ... move to PathConverter
	std::string::size_type s = mFile.find_last_of("/\\");
	if (s == std::string::npos) {
		s = 0;
	}
	else ++s;
	filename = mFile.substr(s), path = mFile.substr(0,s);
	for( std::string::iterator it = filename .begin(); it != filename.end(); ++it)
		*it = tolower( *it);

	// Load multi-part model file, if necessary
	if (configHandleMP) {
		if (ReadMultipartFile())
			return;
	}

	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));

	// Check whether we can read from the file
	if( file.get() == NULL)
		throw DeadlyImportError( "Failed to open MD3 file " + pFile + ".");

	// Check whether the md3 file is large enough to contain the header
	fileSize = (unsigned int)file->FileSize();
	if( fileSize < sizeof(MD3::Header))
		throw DeadlyImportError( "MD3 File is too small.");

	// Allocate storage and copy the contents of the file to a memory buffer
	std::vector<unsigned char> mBuffer2 (fileSize);
	file->Read( &mBuffer2[0], 1, fileSize);
	mBuffer = &mBuffer2[0];

	pcHeader = (BE_NCONST MD3::Header*)mBuffer;

	// Ensure correct endianess
#ifdef AI_BUILD_BIG_ENDIAN

	AI_SWAP4(pcHeader->VERSION);
	AI_SWAP4(pcHeader->FLAGS);
	AI_SWAP4(pcHeader->IDENT);
	AI_SWAP4(pcHeader->NUM_FRAMES);
	AI_SWAP4(pcHeader->NUM_SKINS);
	AI_SWAP4(pcHeader->NUM_SURFACES);
	AI_SWAP4(pcHeader->NUM_TAGS);
	AI_SWAP4(pcHeader->OFS_EOF);
	AI_SWAP4(pcHeader->OFS_FRAMES);
	AI_SWAP4(pcHeader->OFS_SURFACES);
	AI_SWAP4(pcHeader->OFS_TAGS);

#endif

	// Validate the file header
	ValidateHeaderOffsets();

	// Navigate to the list of surfaces
	BE_NCONST MD3::Surface* pcSurfaces = (BE_NCONST MD3::Surface*)(mBuffer + pcHeader->OFS_SURFACES);

	// Navigate to the list of tags
	BE_NCONST MD3::Tag* pcTags = (BE_NCONST MD3::Tag*)(mBuffer + pcHeader->OFS_TAGS);

	// Allocate output storage
	pScene->mNumMeshes = pcHeader->NUM_SURFACES;
	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];

	pScene->mNumMaterials = pcHeader->NUM_SURFACES;
	pScene->mMaterials = new aiMaterial*[pScene->mNumMeshes];

	// Set arrays to zero to ensue proper destruction if an exception is raised
	::memset(pScene->mMeshes,0,pScene->mNumMeshes*sizeof(aiMesh*));
	::memset(pScene->mMaterials,0,pScene->mNumMaterials*sizeof(aiMaterial*));

	// Now read possible skins from .skin file
	Q3Shader::SkinData skins;
	ReadSkin(skins);

	// And check whether we can locate a shader file for this model
	Q3Shader::ShaderData shaders;
	ReadShader(shaders);

	// Adjust all texture paths in the shader
	const char* header_name = pcHeader->NAME;
	if (shaders.blocks.size()) {
		for (std::list< Q3Shader::ShaderDataBlock >::iterator dit = shaders.blocks.begin(); dit != shaders.blocks.end(); ++dit) {
			ConvertPath((*dit).name.c_str(),header_name,(*dit).name);

			for (std::list< Q3Shader::ShaderMapBlock >::iterator mit = (*dit).maps.begin(); mit != (*dit).maps.end(); ++mit) {
				ConvertPath((*mit).name.c_str(),header_name,(*mit).name);
			}
		}
	}

	// Read all surfaces from the file
	unsigned int iNum = pcHeader->NUM_SURFACES;
	unsigned int iNumMaterials = 0;
	while (iNum-- > 0)	{

		// Ensure correct endianess
#ifdef AI_BUILD_BIG_ENDIAN

		AI_SWAP4(pcSurfaces->FLAGS);
		AI_SWAP4(pcSurfaces->IDENT);
		AI_SWAP4(pcSurfaces->NUM_FRAMES);
		AI_SWAP4(pcSurfaces->NUM_SHADER);
		AI_SWAP4(pcSurfaces->NUM_TRIANGLES);
		AI_SWAP4(pcSurfaces->NUM_VERTICES);
		AI_SWAP4(pcSurfaces->OFS_END);
		AI_SWAP4(pcSurfaces->OFS_SHADERS);
		AI_SWAP4(pcSurfaces->OFS_ST);
		AI_SWAP4(pcSurfaces->OFS_TRIANGLES);
		AI_SWAP4(pcSurfaces->OFS_XYZNORMAL);

#endif

		// Validate the surface header
		ValidateSurfaceHeaderOffsets(pcSurfaces);

		// Navigate to the vertex list of the surface
		BE_NCONST MD3::Vertex* pcVertices = (BE_NCONST MD3::Vertex*)
			(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_XYZNORMAL);

		// Navigate to the triangle list of the surface
		BE_NCONST MD3::Triangle* pcTriangles = (BE_NCONST MD3::Triangle*)
			(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_TRIANGLES);

		// Navigate to the texture coordinate list of the surface
		BE_NCONST MD3::TexCoord* pcUVs = (BE_NCONST MD3::TexCoord*)
			(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_ST);

		// Navigate to the shader list of the surface
		BE_NCONST MD3::Shader* pcShaders = (BE_NCONST MD3::Shader*)
			(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_SHADERS);

		// If the submesh is empty ignore it
		if (0 == pcSurfaces->NUM_VERTICES || 0 == pcSurfaces->NUM_TRIANGLES)
		{
			pcSurfaces = (BE_NCONST MD3::Surface*)(((uint8_t*)pcSurfaces) + pcSurfaces->OFS_END);
			pScene->mNumMeshes--;
			continue;
		}

		// Allocate output mesh
		pScene->mMeshes[iNum] = new aiMesh();
		aiMesh* pcMesh = pScene->mMeshes[iNum];

		std::string _texture_name;
		const char* texture_name = NULL;

		// Check whether we have a texture record for this surface in the .skin file
		std::list< Q3Shader::SkinData::TextureEntry >::iterator it = std::find( 
			skins.textures.begin(), skins.textures.end(), pcSurfaces->NAME );

		if (it != skins.textures.end()) {
			texture_name = &*( _texture_name = (*it).second).begin();
			DefaultLogger::get()->debug("MD3: Assigning skin texture " + (*it).second + " to surface " + pcSurfaces->NAME);
			(*it).resolved = true; // mark entry as resolved
		}

		// Get the first shader (= texture?) assigned to the surface
		if (!texture_name && pcSurfaces->NUM_SHADER)	{
			texture_name = pcShaders->NAME;
		}

		std::string convertedPath;
		if (texture_name) {
			ConvertPath(texture_name,header_name,convertedPath);
		}

		const Q3Shader::ShaderDataBlock* shader = NULL;

		// Now search the current shader for a record with this name (
		// excluding texture file extension)
		if (shaders.blocks.size()) {

			std::string::size_type s = convertedPath.find_last_of('.');
			if (s == std::string::npos)
				s = convertedPath.length();

			const std::string without_ext = convertedPath.substr(0,s);
			std::list< Q3Shader::ShaderDataBlock >::const_iterator dit = std::find(shaders.blocks.begin(),shaders.blocks.end(),without_ext);
			if (dit != shaders.blocks.end()) {
				// Hurra, wir haben einen. Tolle Sache.
				shader = &*dit;
				DefaultLogger::get()->info("Found shader record for " +without_ext );
			}
			else DefaultLogger::get()->warn("Unable to find shader record for " +without_ext );
		}

		MaterialHelper* pcHelper = new MaterialHelper();

		const int iMode = (int)aiShadingMode_Gouraud;
		pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);

		// Add a small ambient color value - Quake 3 seems to have one
		aiColor3D clr;
		clr.b = clr.g = clr.r = 0.05f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);

		clr.b = clr.g = clr.r = 1.0f;
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
		pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);

		// use surface name + skin_name as material name
		aiString name;
		name.Set("MD3_[" + configSkinFile + "][" + pcSurfaces->NAME + "]");
		pcHelper->AddProperty(&name,AI_MATKEY_NAME);

		if (!shader) {
			// Setup dummy texture file name to ensure UV coordinates are kept during postprocessing
			aiString szString;
			if (convertedPath.length())	{
				szString.Set(convertedPath);
			}
			else	{
				DefaultLogger::get()->warn("Texture file name has zero length. Using default name");
				szString.Set("dummy_texture.bmp");
			}
			pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));

			// prevent transparency by default
			int no_alpha = aiTextureFlags_IgnoreAlpha;
			pcHelper->AddProperty(&no_alpha,1,AI_MATKEY_TEXFLAGS_DIFFUSE(0));
		}
		else {
			Q3Shader::ConvertShaderToMaterial(pcHelper,*shader);
		}

		pScene->mMaterials[iNumMaterials] = (aiMaterial*)pcHelper;
		pcMesh->mMaterialIndex = iNumMaterials++;

			// Ensure correct endianess
#ifdef AI_BUILD_BIG_ENDIAN

		for (uint32_t i = 0; i < pcSurfaces->NUM_VERTICES;++i)	{
			AI_SWAP2( pcVertices[i].NORMAL );
			AI_SWAP2( pcVertices[i].X );
			AI_SWAP2( pcVertices[i].Y );
			AI_SWAP2( pcVertices[i].Z );

			AI_SWAP4( pcUVs[i].U );
			AI_SWAP4( pcUVs[i].U );
		}
		for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i)	{
			AI_SWAP4(pcTriangles[i].INDEXES[0]);
			AI_SWAP4(pcTriangles[i].INDEXES[1]);
			AI_SWAP4(pcTriangles[i].INDEXES[2]);
		}

#endif

		// Fill mesh information
		pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;

		pcMesh->mNumVertices		= pcSurfaces->NUM_TRIANGLES*3;
		pcMesh->mNumFaces			= pcSurfaces->NUM_TRIANGLES;
		pcMesh->mFaces				= new aiFace[pcSurfaces->NUM_TRIANGLES];
		pcMesh->mNormals			= new aiVector3D[pcMesh->mNumVertices];
		pcMesh->mVertices			= new aiVector3D[pcMesh->mNumVertices];
		pcMesh->mTextureCoords[0]	= new aiVector3D[pcMesh->mNumVertices];
		pcMesh->mNumUVComponents[0] = 2;

		// Fill in all triangles
		unsigned int iCurrent = 0;
		for (unsigned int i = 0; i < (unsigned int)pcSurfaces->NUM_TRIANGLES;++i)	{
			pcMesh->mFaces[i].mIndices = new unsigned int[3];
			pcMesh->mFaces[i].mNumIndices = 3;

			//unsigned int iTemp = iCurrent;
			for (unsigned int c = 0; c < 3;++c,++iCurrent)	{
				pcMesh->mFaces[i].mIndices[c] = iCurrent;

				// Read vertices
				aiVector3D& vec = pcMesh->mVertices[iCurrent];
				vec.x = pcVertices[ pcTriangles->INDEXES[c]].X*AI_MD3_XYZ_SCALE;
				vec.y = pcVertices[ pcTriangles->INDEXES[c]].Y*AI_MD3_XYZ_SCALE;
				vec.z = pcVertices[ pcTriangles->INDEXES[c]].Z*AI_MD3_XYZ_SCALE;

				// Convert the normal vector to uncompressed float3 format
				aiVector3D& nor = pcMesh->mNormals[iCurrent];
				LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,(float*)&nor);

				// Read texture coordinates
				pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
				pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
			}
			// Flip face order if necessary
			if (!shader || shader->cull == Q3Shader::CULL_CW) {
				std::swap(pcMesh->mFaces[i].mIndices[2],pcMesh->mFaces[i].mIndices[1]);
			}
			pcTriangles++;
		}
	
		// Go to the next surface
		pcSurfaces = (BE_NCONST MD3::Surface*)(((unsigned char*)pcSurfaces) + pcSurfaces->OFS_END);
	}

	// For debugging purposes: check whether we found matches for all entries in the skins file
	if (!DefaultLogger::isNullLogger()) {
		for (std::list< Q3Shader::SkinData::TextureEntry>::const_iterator it = skins.textures.begin();it != skins.textures.end(); ++it) {
			if (!(*it).resolved) {
				DefaultLogger::get()->error("MD3: Failed to match skin " + (*it).first + " to surface " + (*it).second);
			}
		}
	}

	if (!pScene->mNumMeshes)
		throw DeadlyImportError( "MD3: File contains no valid mesh");
	pScene->mNumMaterials = iNumMaterials;

	// Now we need to generate an empty node graph
	pScene->mRootNode = new aiNode("<MD3Root>");
	pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
	pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];

	// Attach tiny children for all tags
	if (pcHeader->NUM_TAGS) {
		pScene->mRootNode->mNumChildren = pcHeader->NUM_TAGS;
		pScene->mRootNode->mChildren = new aiNode*[pcHeader->NUM_TAGS];

		for (unsigned int i = 0; i < pcHeader->NUM_TAGS; ++i, ++pcTags) {

			aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();
			nd->mName.Set((const char*)pcTags->NAME);
			nd->mParent = pScene->mRootNode;

			AI_SWAP4(pcTags->origin.x);
			AI_SWAP4(pcTags->origin.y);
			AI_SWAP4(pcTags->origin.z);

			// Copy local origin, again flip z,y
			nd->mTransformation.a4 = pcTags->origin.x;
			nd->mTransformation.b4 = pcTags->origin.y;
			nd->mTransformation.c4 = pcTags->origin.z;

			// Copy rest of transformation (need to transpose to match row-order matrix)
			for (unsigned int a = 0; a < 3;++a) {
				for (unsigned int m = 0; m < 3;++m) {
					nd->mTransformation[m][a] = pcTags->orientation[a][m];
					AI_SWAP4(nd->mTransformation[m][a]);
				}
			}
		}
	}

	for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
		pScene->mRootNode->mMeshes[i] = i;

	// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
	pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f,
		0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f);
}