www.pudn.com > zfxcengine-0.1.0.zip > ceMeshFormatQ3BSP.cpp


#include "Geometry/ceMeshFormatQ3BSP.h" 
#include "Core/ceExceptions.h" 
namespace ZFXCE { 
	//------------------------------------------------------------------------------ 
	const INT VERION_Q3LEVEL = 46; 
 
	//------------------------------------------------------------------------------ 
	ceMeshFormatQ3BSP::ceMeshFormatQ3BSP()  
	{ 
		Desc = std::string("Quake3 Maps"); 
		FileExt = std::string("bsp"); 
		FileType = CE_VFS_BIN; 
		m_pEntityData = NULL; 
		m_uiNumOfVertices =0; 
		m_uiNumOfIndices=0; 
		m_uiNumOfFaces=0; 
		m_uiNumOfTextures=0; 
		m_uiNumOfLightmaps=0; 
	} 
	//------------------------------------------------------------------------------ 
	ceMeshFormatQ3BSP::~ceMeshFormatQ3BSP() 
	{ 
		if (0 != m_RenderVertices.size()) { 
			for (vector::iterator it = m_RenderVertices.begin(); 
				it != m_RenderVertices.end(); ++it) { 
				delete *it; 
			} 
			m_RenderVertices.clear(); 
		} 
 
		if (0 != this->m_Vertices.size()) { 
			for (vector::iterator it = m_Vertices.begin();  
				it != m_Vertices.end(); ++it){ 
				delete *it; 
			} 
			m_Vertices.clear(); 
		} 
 
		if (0 != m_Indices.size())  
			m_Indices.clear(); 
 
		if (0 != m_Lightmaps.size())  
			m_Lightmaps.clear(); 
 
		if (0 != m_Lumps.size())  
			m_Lumps.clear(); 
		 
		if (0 != m_Faces.size()) { 
			for (vector::iterator it = m_Faces.begin(); it != m_Faces.end(); ++it) { 
				delete *it; 
			} 
			m_Faces.clear(); 
		} 
 
		if (0 != m_Textures.size()) 
			m_Textures.clear(); 
		delete [] m_pEntityData; 
		m_pEntityData = NULL; 
	} 
	//------------------------------------------------------------------------------ 
	ceMesh *ceMeshFormatQ3BSP::Load(BYTE *pData, size_t sSize) 
	{ 
		PUSH_FUNCTION; 
 
		LoadQ3BSP(pData, sSize); 
		return (ConvertQ3BSPToMesh()); 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::ValidateFormat(BYTE *pData, size_t sSize,  
		UINT &uiOffset, sQ3BSPHeader *pHeader) 
	{ 
		PUSH_FUNCTION; 
 
		// Read in header 
		pHeader = (sQ3BSPHeader*) pData; 
		uiOffset += sizeof(sQ3BSPHeader); 
 
		// Version and identify string validation 
		ce_check (VERION_Q3LEVEL == pHeader->iVersion, "False fileversion for Q3 level"); 
		if (pHeader->strID[0] != 'I' || pHeader->strID[1] != 'B' || pHeader->strID[2] != 'S'  
			|| pHeader->strID[3] != 'P')  
		{ 
			ce_warn(false,"Falscher Identifikationsstring!"); 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::GetLumps(BYTE *pData, size_t sSize, UINT &uiOffset, 
		std::vector &Lumps) 
	{ 
		PUSH_FUNCTION; 
 
		for (UINT l=0; l < kMaxLumps; ++l) { 
			sQ3BSPLump Lump; 
			memcpy(&Lump, pData+uiOffset, sizeof(sQ3BSPLump) ); 
			uiOffset += sizeof(sQ3BSPLump); 
			Lumps.push_back(Lump); 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::CountLumps() 
	{ 
		PUSH_FUNCTION; 
 
		m_uiNumOfVertices	= m_Lumps[kVertices].iSize / sizeof(sQ3BSPVertex); 
		m_uiNumOfIndices	= m_Lumps[kMeshVerts].iSize / sizeof(INT); 
		m_uiNumOfFaces		= m_Lumps[kFaces].iSize / sizeof(sQ3BSPFace); 
		m_uiNumOfTextures	= m_Lumps[kTextures].iSize / sizeof(sQ3BSPTexture); 
		m_uiNumOfLightmaps	= m_Lumps[kLightmaps].iSize / sizeof(sQ3BSPLightmap); 
	} 
	//------------------------------------------------------------------------------ 
	sQ3BSPVertex *ceMeshFormatQ3BSP::GetVertices(BYTE *pData, size_t sSize, UINT &uiOffset) 
	{ 
		PUSH_FUNCTION; 
 
		sQ3BSPVertex* Vertices = new sQ3BSPVertex[m_uiNumOfVertices]; 
		uiOffset = m_Lumps[kVertices].iOffset; 
		memcpy(&Vertices[0], pData+uiOffset, sizeof(sQ3BSPVertex) * m_uiNumOfVertices); 
		for (size_t i=0; i Lightmaps; 
		uiOffset = m_Lumps[kLightmaps].iOffset; 
		for (UINT l=0; l < m_uiNumOfLightmaps; ++l) { 
			sQ3BSPLightmap Lightmap; 
			memcpy(&Lightmap, pData+uiOffset, sizeof(sQ3BSPLightmap) ); 
			uiOffset += sizeof(sQ3BSPLightmap); 
			ChangeGamma( (BYTE*) &Lightmap.bLMapData[0], 128*128*3, 3.0f); 
			m_Lightmaps.push_back(Lightmap); 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::GetEntityTest(BYTE *pData, size_t sSize, UINT &uiOffset) 
	{ 
		PUSH_FUNCTION; 
 
		m_pEntityData = new CHAR[m_Lumps[kEntities].iSize]; 
		uiOffset = m_Lumps[kEntities].iOffset; 
		memcpy(&m_pEntityData[0], pData+uiOffset, sizeof(CHAR) * m_Lumps[kEntities].iSize ); 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::GetRenderVertices(BYTE *pData, size_t sSize,  
		UINT &uiOffset, const sQ3BSPVertex* Vertices) 
	{ 
		sRenderVertex* RenderVertices = new sRenderVertex[m_uiNumOfVertices]; 
		for (UINT v=0; v < m_uiNumOfVertices; ++v) { 
			memcpy(&RenderVertices[v].vPosition, &Vertices[v].vPosition, sizeof(ceVec3f) ); 
			memcpy(&RenderVertices[v].vTC, &Vertices[v].vTexCoord, sizeof(ceVec2f) ); 
			 
			// light maps 
			memcpy(&RenderVertices[v].vTCLightmap, &Vertices[v].vLightmap, sizeof(ceVec2f)); 
 
			// Brighten up the vertex colors a little bit 
			for (UINT c=0; c < 4; c++) { 
				const FLOAT Increase = 3.5f; 
				RenderVertices[v].Color[c] = (UCHAR) (Vertices[v].bColor[c] * Increase); 
			} 
			m_RenderVertices.push_back(&RenderVertices[v]); 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::LoadEntities(const std::string &strEntityText) 
	{ 
		PUSH_FUNCTION; 
 
		const char seps[]   = " \t\n\""; 
		char* token = strtok((char*) strEntityText.c_str(), seps ); 
		while(true) { 
			if(!token) 
				break; 
 
			if (strcmp(token, "info_player_deathmatch") == 0 || 
				strcmp(token, "info_player_start") == 0) { 
				token = strtok(NULL, seps); 
				if (0 == strcmp(token, "angle")) { 
					// skip angle, not needed 
					token = strtok(NULL, seps); 
 
					// read next token after angle 
					token = strtok(NULL, seps); 
				} 
				if(strcmp(token, "origin") == 0) { 
					const FLOAT x = (FLOAT)atof(strtok(NULL, seps) ); 
					const FLOAT y  = (FLOAT)atof(strtok(NULL, seps) ); 
					const FLOAT z = (FLOAT)atof(strtok(NULL, seps) ); 
 
					tStartPosition Pos; 
					Pos.vPosition = ceVec3f(x,y,z); 
					Pos.vLookAt = ceVec3f(x,y+1.0f, z); 
					m_StartPositions.push_back(Pos); 
				} 
				else 
					cout << "Unknown Token: \"" << token << "\""<< endl; 
			} 
 
			// get next token 
			token = strtok(NULL, seps); 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::ChangeGamma(BYTE *pImage, INT size, FLOAT factor) 
	{ 
		PUSH_FUNCTION; 
		 
		// Go through every pixel in the lightmap 
		for (INT i = 0; i < size / 3; i++, pImage += 3) { 
			FLOAT scale = 1.0f, temp = 0.0f; 
			FLOAT r = 0, g = 0, b = 0; 
 
			// Extract the current RGB values 
			r = (FLOAT) pImage[0]; 
			g = (FLOAT) pImage[1]; 
			b = (FLOAT) pImage[2]; 
 
			// Multiply the factor by the RGB values, while keeping it to a 255 ratio 
			const FLOAT fVal = 1 / 255.0f; 
			r = r * factor * fVal; 
		    g = g * factor * fVal; 
		    b = b * factor * fVal; 
 
			// Check if the the values went past the highest value 
			if (r > 1.0f && (temp = (1.0f/r)) < scale) scale = temp; 
			if (g > 1.0f && (temp = (1.0f/g)) < scale) scale = temp; 
			if (b > 1.0f && (temp = (1.0f/b)) < scale) scale = temp; 
 
			// Get the scale for this pixel and multiply it by our pixel values 
			scale*=255.0f; 
			r*=scale; 
			g*=scale;    
			b*=scale; 
 
			// Assign the new gamma'nized RGB values to our image 
			pImage[0] = (BYTE)r; 
			pImage[1] = (BYTE)g; 
			pImage[2] = (BYTE)b; 
		} 
	} 
	//------------------------------------------------------------------------------ 
	void ceMeshFormatQ3BSP::LoadQ3BSP(BYTE *pData, size_t sSize) 
	{ 
		PUSH_FUNCTION; 
 
		// Problems : Not tested in this format, texture support does not work  
		// (see CreateCube with texture name for examples) 
		// Eventually No light map support 
		// Questions to : kim.kulling@web.de 
		 
		// Init offset for parse level data buffer 
		UINT uiOffset = 0; 
 
		// Read in header 
		sQ3BSPHeader *pHeader = NULL; 
		ValidateFormat(pData, sSize, uiOffset, pHeader); 
		 
		// Read in lumps of level 
		GetLumps(pData, sSize, uiOffset, m_Lumps); 
		 
		// Count the different lumps 
		CountLumps(); 
 
		// Read in Vertices 
		sQ3BSPVertex* Vertices = GetVertices(pData, sSize, uiOffset); 
 
		// Read in Indices 
		GetIndices(pData, sSize, uiOffset); 
		 
		// Read Faces 
		GetFaces(pData, sSize, uiOffset); 
 
		// Read Textures 
		GetTextures(pData, sSize, uiOffset); 
 
		// Read Lightmaps 
		GetLightmaps(pData, sSize, uiOffset); 
 
		// Load entity text 
		GetEntityTest(pData, sSize, uiOffset); 
 
		// Load the entities 
		LoadEntities(m_pEntityData); 
		 
		// Set render verties 
		GetRenderVertices(pData, sSize, uiOffset, Vertices); 
	} 
	//------------------------------------------------------------------------------ 
	ceMesh *ceMeshFormatQ3BSP::ConvertQ3BSPToMesh() 
	{ 
		ceMesh *pMesh = new ceMesh(); 
		 
		std::vector vertices; 
		std::vector colors; 
		unsigned char col[4]; 
		ceColorRGBA temp; 
		std::vector TexturCoords; 
		std::vector LightCoords; 
		ceVec2f texcoor, lightcoor; 
		pMesh->SetTextureNames(m_vTextureList); 
		for (std::vector::iterator it = m_RenderVertices.begin();  
			it != m_RenderVertices.end(); ++it) { 
			vertices.push_back((*it)->vPosition); 
			memcpy(&col[0], (*it)->Color, sizeof(unsigned char)*4); 
			temp.r = col[0]; 
			temp.g = col[1]; 
			temp.b = col[2]; 
			temp.a = col[3]; 
			colors.push_back(temp); 
			TexturCoords.push_back((*it)->vTC); 
			LightCoords.push_back((*it)->vTCLightmap); 
		}	 
		 
		// Loop over all faces 
		std::vector faces; 
		for (std::vector::iterator it = m_Faces.begin(); it != m_Faces.end(); ++it) { 
			Face face; 
			face.UIIndices.push_back((*it)->iVertexIndex); 
			face.m_vTexID = (*it)->iTextureID; 
			face.m_uiLightMapID = (*it)->iLightmapID; 
			faces.push_back(face); 
		} 
		pMesh->SetFaces(faces); 
		pMesh->SetVertices(vertices); 
		pMesh->SetColor(colors); 
 
		return pMesh; 
	} 
	//------------------------------------------------------------------------------ 
 
} // Namespace ZFXCE