加载TLBB场景(二)

#include "StdAfx.h"
#include "TerrainScene.h"
#include <tinyxml/tinyxml.h>

#ifdef _DEBUG
#pragma comment(lib, "tinyxml_d.lib")
#else
#pragma comment(lib, "tinyxml.lib")
#endif

struct CUSTOMVERTEX
{
	float x, y, z;	   // 世界坐标
	float u, v;      // 纹理坐标
};

struct GeometryData
{
	unsigned int			numVertices;
	unsigned int			numIndices;
	std::vector<CUSTOMVERTEX>	vertexData;	
	std::vector<unsigned int>	indexData;
	TexturePtr			pTexture;
};

struct PixMap
{
	int textureId;
	float left;
	float top;
	float right;
	float bottom;
};	

struct GridHeader
{
	unsigned int nMagic;
	// 版本号
	unsigned int nVersion;
	// 地表宽度(横向格子数)
	int nWidth;
	// 地表高度(纵向格子数)
	int nHeight;
};

struct GridInfo
{
	// 该值即为pixelmap的索引(第几个pixelmap)
	short    nFirstLayer;
	// 对nFirstLayer的操作,取值是上面几个定义的宏,可以互相组合
	unsigned char    nFirstLayerOp;
	// 该值为pixelmap的索引
	//天龙八部的地表最多可以两层融合,说白了就是每个点里有两层UV,这里为第二层pixelmap的索引
	short    nSecondLayer;
	// 对nSecondLayer的操作,取值同nFirstLayerOp
	unsigned char    nSecondLayerOp;
	// 对格子的三角形的操作,可能取值如下
	//    0正常三角形索引
	//    1不同于正常的三角形索引
	unsigned char    IndexOrder;

	// 图片水平翻转,即左右翻转
#define FLIP_HORIZINTAL 1
	// 图片垂直翻转,即上下翻转
#define FLIP_VERTICAL 2
	// 逆时针旋转90度
#define ANTICLOCKWISE_90 4
	// 以三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则把右上的坐标复制到左下
#define FLIP_DIAGONAL 8

};

CTerrainScene::CTerrainScene(void)
{
	m_pSceneManager  = NULL;
	m_iTerrainWidth  = 0;
	m_iTerrainHeight = 0;
	m_pHeightMapData = NULL;

	for( int idx = 0; idx < 3; ++idx )
	{
		m_fTerrainScale[idx] = 1.0f;
	}
}

CTerrainScene::~CTerrainScene(void)
{
	ClearScene();

	m_pSceneManager = NULL;
}

void CTerrainScene::SetSceneManager( SceneManager* pManager )
{
	m_pSceneManager = pManager;
}

void CTerrainScene::LoadScene( const char* strFileName, SceneNode* pRootNode )
{
	if( m_pSceneManager == NULL )
		return;

	TiXmlDocument doc;

	String FileName = strFileName;
	String FullPath = "";
	{
		ResourceGroupManager::LocationList locates = ResourceGroupManager::getSingleton().getResourceLocationList(
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

		ResourceGroupManager::LocationList::iterator it_begin = locates.begin();
		ResourceGroupManager::LocationList::iterator it_end = locates.end();
		while( it_begin != it_end )
		{		
			FullPath = (*it_begin)->archive->getName() + String("/") + FileName; 
			FILE* pFile = fopen( FullPath.c_str(), "rb" );
			if( pFile != NULL )
			{
				fclose(pFile);
				break;
			}
			++it_begin;
		}
		if( it_begin == it_end )
			return;
	}	

	doc.LoadFile(FullPath.c_str(), TIXML_ENCODING_UTF8);
	TiXmlElement* pRoot = doc.FirstChildElement("Scene");
	if( pRoot == NULL )
		return;

	TiXmlElement* pChild = pRoot->FirstChildElement();

	while( pChild != NULL )
	{	
		const char* pUtf8NodeName = pChild->Value();
		if( pUtf8NodeName != NULL )
		{
			if( strcmp( pUtf8NodeName, "Terrain") == 0 )
			{
				const char* pUtf8FileName = pChild->Attribute("filename");
				if( pUtf8FileName != NULL )
				{
					int len = MultiByteToWideChar( CP_UTF8, 0, pUtf8FileName, -1, NULL, 0 );
					wchar_t* pwFileName = new wchar_t[len];
					MultiByteToWideChar(CP_UTF8, 0, pUtf8FileName, -1, pwFileName, len );		
					len = WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, NULL, 0, NULL, NULL );
					char* pFileName = new char[len];
					WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, pFileName, len, NULL, NULL );
					delete[] pwFileName;

					LoadTerrain(pFileName, pRootNode);

					delete pFileName;
				}
			}
			else if( strcmp( pUtf8NodeName, "Object") == 0 )
			{
				const char* pUtf8Type = pChild->Attribute("type");
				if( stricmp(pUtf8Type, "StaticEntity") == 0 ||
					stricmp(pUtf8Type, "Model")  == 0 )
				{
					SceneNode* pEntityNode = NULL;
					float pos[3] = {0.0f, 0.0f, 0.0f};
					float orientation[4] = {1.0f, 0.0f, 0.0f, 0.0f};
					float scale[3] = {1.0f, 1.0f, 1.0f};

					TiXmlElement* pProperty = pChild->FirstChildElement();
					while( pProperty != NULL )
					{
						const char* pUtf8Name = pProperty->Attribute("name");
						int tagMesh = stricmp(pUtf8Name, "mesh name");
						int tagModel = stricmp(pUtf8Name, "model name");
						if(  tagMesh == 0 || tagModel == 0 )
						{
							const char* pUtf8Value = pProperty->Attribute("value");
							if( pUtf8Value != NULL )
							{
								int len = MultiByteToWideChar(CP_UTF8, 0, pUtf8Value, -1, NULL, 0);
								wchar_t* pwValue = new wchar_t[len];
								MultiByteToWideChar(CP_UTF8, 0, pUtf8Value, -1, pwValue, len);
								len = WideCharToMultiByte(CP_ACP, 0, pwValue, -1, NULL, 0, NULL, NULL);
								char* pMeshName = new char[len];
								WideCharToMultiByte(CP_ACP, 0, pwValue, -1, pMeshName, len, NULL, NULL);

								pEntityNode = pRootNode->createChildSceneNode();
								if( tagMesh == 0 )
								{
									Entity* pEntity = NULL;
									if( ResourceGroupManager::getSingleton().resourceExists(
										ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 
										pMeshName) )
									{
										pEntity = m_pSceneManager->createEntity(pMeshName);
										pEntityNode->attachObject(pEntity);
									}
								}
								else
								{
									LoadModelObject( pMeshName, pEntityNode);
								}

								delete[] pwValue;
								delete[] pMeshName;
							}
						}
						else if( stricmp(pUtf8Name, "position") == 0 )
						{
							const char* pUtf8Value = pProperty->Attribute("value");
							if( pUtf8Value != NULL )
							{
								int len = strlen(pUtf8Value);
								char* pValue = new char[len + 1];

								const char* p1 = pUtf8Value;
								const char* p2 = pUtf8Value;
								int idx = 0;

								while( *p1 != NULL && idx < 3 )
								{
									if( *p1 == ' ' )
									{
										int interval = p1 - p2;
										memcpy( pValue, p2, interval);
										pValue[interval] = NULL;
										pos[idx] = atof(pValue);
										p2 = p1 + 1;
										++idx;
									}
									++p1;
								}
								if( idx < 3 )
								{
									int interval = p1 - p2;
									memcpy( pValue, p2, interval);
									pValue[interval] = NULL;
									pos[idx] = atof(pValue);
								}

								delete[] pValue;
							}
						}
						else if( stricmp(pUtf8Name, "orientation") == 0 )
						{
							const char* pUtf8Value = pProperty->Attribute("value");
							if( pUtf8Value != NULL )
							{
								int len = strlen(pUtf8Value);
								char* pValue = new char[len + 1];

								const char* p1 = pUtf8Value;
								const char* p2 = pUtf8Value;
								int idx = 0;

								while( *p1 != NULL && idx < 4 )
								{
									if( *p1 == ' ' )
									{
										int interval = p1 - p2;
										memcpy( pValue, p2, interval);
										pValue[interval] = NULL;
										orientation[idx] = atof(pValue);
										p2 = p1 + 1;
										++idx;
									}
									++p1;
								}
								if( idx < 4 )
								{
									int interval = p1 - p2;
									memcpy( pValue, p2, interval);
									pValue[interval] = NULL;
									orientation[idx] = atof(pValue);
								}

								delete[] pValue;
							}
						}
						else if( stricmp(pUtf8Name, "scale") == 0 )
						{
							const char* pUtf8Value = pProperty->Attribute("value");
							if( pUtf8Value != NULL )
							{
								int len = strlen(pUtf8Value);
								char* pValue = new char[len + 1];

								const char* p1 = pUtf8Value;
								const char* p2 = pUtf8Value;
								int idx = 0;

								while( *p1 != NULL && idx < 3 )
								{
									if( *p1 == ' ' )
									{
										int interval = p1 - p2;
										memcpy( pValue, p2, interval);
										pValue[interval] = NULL;
										scale[idx] = atof(pValue);
										p2 = p1 + 1;
										++idx;
									}
									++p1;
								}
								if( idx < 3 )
								{
									int interval = p1 - p2;
									memcpy( pValue, p2, interval);
									pValue[interval] = NULL;
									scale[idx] = atof(pValue);
								}

								delete[] pValue;
							}
						}

						pProperty = pProperty->NextSiblingElement();
					}

					if( pEntityNode != NULL )
					{
						pEntityNode->setScale(scale[0], scale[1], scale[2]);
						pEntityNode->setPosition(pos[0], pos[1], pos[2]);
						pEntityNode->setOrientation(orientation[0], orientation[1], orientation[2], orientation[3]);
					}
				}
			}
		}

		pChild = pChild->NextSiblingElement();
	}
}

void CTerrainScene::LoadTerrain( const char* strFileName, SceneNode* pRootNode )
{
	if( m_pSceneManager == NULL )
		return;

	String FileName = strFileName;
	String FullPath = "";
	{
		ResourceGroupManager::LocationList locates = ResourceGroupManager::getSingleton().getResourceLocationList(
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

		ResourceGroupManager::LocationList::iterator it_begin = locates.begin();
		ResourceGroupManager::LocationList::iterator it_end = locates.end();
		while( it_begin != it_end )
		{		
			FullPath = (*it_begin)->archive->getName() + String("/") + FileName; 
			FILE* pFile = fopen( FullPath.c_str(), "rb" );
			if( pFile != NULL )
			{
				fclose(pFile);
				break;
			}
			++it_begin;
		}
		if(it_begin == it_end)
			return; 
	}
	TiXmlDocument doc;
	doc.LoadFile( FullPath.c_str(), TIXML_ENCODING_UTF8);
	TiXmlElement* pTerrainNode = doc.RootElement();
	if( pTerrainNode == NULL )
		return;
	const char* pUtf8XSize = pTerrainNode->Attribute("xsize");
	const char* pUtf8ZSize = pTerrainNode->Attribute("zsize");
	
	m_iTerrainWidth		= atoi(pUtf8XSize) + 1;
	m_iTerrainHeight	= atoi(pUtf8ZSize) + 1;

	TiXmlElement* texturesElement = pTerrainNode->FirstChildElement("textures");
	TiXmlElement* textureElement = texturesElement->FirstChildElement();
	int size_textures = 0;

	std::vector<TexturePtr> list_textures;

	while( textureElement != NULL )
	{	
		const char* p = textureElement->Attribute("filename");

		int len = MultiByteToWideChar(CP_UTF8, 0, p, -1, 0, 0 );
		wchar_t* wFilename = new wchar_t[len];
		MultiByteToWideChar(CP_UTF8, 0, p, -1, wFilename, len);

		len = WideCharToMultiByte(CP_ACP, 0, wFilename, -1, 0, 0, NULL, NULL);
		char* Filename = new char[len];
		WideCharToMultiByte(CP_ACP, 0, wFilename, -1, Filename, len, NULL, NULL);

		TexturePtr texturePtr = 
			TextureManager::getSingleton().getByName( Filename );
		if( texturePtr.isNull() )
		{	
			texturePtr = TextureManager::getSingleton().create( Filename, 
				ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );			    
			texturePtr->load();
		}

		list_textures.push_back(texturePtr);

		++size_textures;

		delete[] wFilename;
		delete[] Filename;

		textureElement = textureElement->NextSiblingElement();
	}

	TiXmlElement* pixmapsElement = pTerrainNode->FirstChildElement("pixmaps");
	TiXmlElement* pixmapElement = pixmapsElement->FirstChildElement();

	std::vector<PixMap> pixmaps;

	while( pixmapElement != NULL )
	{	
		PixMap pixmap;

		const char* p = pixmapElement->Attribute("textureId");
		pixmap.textureId = atof(p);
		const char* pLeftVal = pixmapElement->Attribute("left");
		if( pLeftVal != NULL )
			pixmap.left = atof(pLeftVal);
		else
			pixmap.left = 0.0f;

		const char* pTopVal = pixmapElement->Attribute("top");
		if( pTopVal != NULL )
			pixmap.top = atof(pTopVal);
		else
			pixmap.top = 0.0f;

		const char* pRightVal = pixmapElement->Attribute("right");
		if( pRightVal != NULL )
			pixmap.right = atof(pRightVal);
		else
			pixmap.right = 1.0f;

		const char* pBottomVal = pixmapElement->Attribute("bottom");
		if( pBottomVal != NULL )
			pixmap.bottom = atof(pBottomVal);
		else
			pixmap.bottom = 1.0f;

		pixmaps.push_back(pixmap);

		pixmapElement = pixmapElement->NextSiblingElement();
	}

	TiXmlElement* height_map_element =
		pTerrainNode->FirstChildElement("heightmap");
	const char* height_map_filename = height_map_element->Attribute("filename");
	TiXmlElement* gridinfo_element =
		pTerrainNode->FirstChildElement("gridInfo");
	const char* gridinfo_filename = gridinfo_element->Attribute("filename");

	int height_map_width = 0;
	int height_map_height = 0;

	if( height_map_filename != NULL )
	{
		int len = MultiByteToWideChar( CP_UTF8, 0, height_map_filename, -1, NULL, 0 );
		wchar_t* pwFileName = new wchar_t[len];
		MultiByteToWideChar(CP_UTF8, 0, height_map_filename, -1, pwFileName, len );		
		len = WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, NULL, 0, NULL, NULL );
		char* pFileName = new char[len];
		WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, pFileName, len, NULL, NULL );
		delete[] pwFileName;

		FileName = pFileName;
		delete[] pFileName;
		{
			ResourceGroupManager::LocationList locates = ResourceGroupManager::getSingleton().getResourceLocationList(
				ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

			ResourceGroupManager::LocationList::iterator it_begin = locates.begin();
			ResourceGroupManager::LocationList::iterator it_end = locates.end();
			while( it_begin != it_end )
			{		
				FullPath = (*it_begin)->archive->getName() + String("/") + FileName; 
				FILE* pFile = fopen( FullPath.c_str(), "rb" );
				if( pFile != NULL )
				{
					fclose(pFile);
					break;
				}
				++it_begin;
			}
			if(it_begin != it_end)
			{
				FILE* pHeightFile = fopen( FullPath.c_str(), "rb" );
				fseek( pHeightFile, 8, SEEK_CUR );
				fread( &height_map_width, sizeof(unsigned int), 1, pHeightFile );
				fread( &height_map_height, sizeof(unsigned int), 1, pHeightFile );
				m_pHeightMapData = new float[height_map_width * height_map_height];	
				fread( m_pHeightMapData, sizeof(float), 
					height_map_width * height_map_height, pHeightFile );	
				fclose( pHeightFile );
			}
		}		
	}

	GridInfo* pGridData = NULL;
	unsigned int grid_width = 0;
	unsigned int grid_height = 0;
	if( gridinfo_filename != NULL )
	{
		int len = MultiByteToWideChar( CP_UTF8, 0, gridinfo_filename, -1, NULL, 0 );
		wchar_t* pwFileName = new wchar_t[len];
		MultiByteToWideChar(CP_UTF8, 0, gridinfo_filename, -1, pwFileName, len );		
		len = WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, NULL, 0, NULL, NULL );
		char* pFileName = new char[len];
		WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, pFileName, len, NULL, NULL );
		delete[] pwFileName;

		FileName = pFileName;		
		delete[] pFileName;
		{
			ResourceGroupManager::LocationList locates = ResourceGroupManager::getSingleton().getResourceLocationList(
				ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

			ResourceGroupManager::LocationList::iterator it_begin = locates.begin();
			ResourceGroupManager::LocationList::iterator it_end = locates.end();
			while( it_begin != it_end )
			{		
				FullPath = (*it_begin)->archive->getName() + String("/") + FileName; 
				FILE* pFile = fopen( FullPath.c_str(), "rb" );
				if( pFile != NULL )
				{
					fclose(pFile);
					break;
				}
				++it_begin;
			}
			if(it_begin != it_end)
			{
				LoadGridInfo( FullPath.c_str(), NULL, &grid_width, &grid_height );
				pGridData = new GridInfo[grid_width * grid_height];
				LoadGridInfo( FullPath.c_str(), pGridData, &grid_width, &grid_height );
			}
		}		
	}

	TiXmlElement* ScaleNode =
		pTerrainNode->FirstChildElement("scale");
	if( ScaleNode != NULL )
	{
		const char* XScale = ScaleNode->Attribute("x");
		const char* YScale = ScaleNode->Attribute("y");
		const char* ZScale = ScaleNode->Attribute("z");
		if( XScale != NULL && YScale != NULL && ZScale != NULL )
		{
			m_fTerrainScale[0] = atof(XScale);
			m_fTerrainScale[1] = atof(YScale);
			m_fTerrainScale[2] = atof(ZScale);
		}
	}

	float Min[3] = {  999999,  999999,  999999 };
	float Max[3] = { -999999, -999999, -999999 };
	Min[0] = -m_fTerrainScale[0] * m_iTerrainWidth / 2.0f;	
	Max[0] =  m_fTerrainScale[0] * m_iTerrainWidth / 2.0f;
	Min[2] = -m_fTerrainScale[2] * m_iTerrainHeight / 2.0f;
	Max[2] =  m_fTerrainScale[2] * m_iTerrainHeight / 2.0f;

	float height_map_value = 0.0f;
	CUSTOMVERTEX* pTerrainVertices = new CUSTOMVERTEX[m_iTerrainWidth * m_iTerrainHeight];
	for( int i = 0; i < m_iTerrainHeight; ++i )
	{
		for( int j = 0; j < m_iTerrainWidth; ++j )
		{
			int idx = i * m_iTerrainWidth + j;

			if( m_pHeightMapData != NULL )
				height_map_value = m_pHeightMapData[idx];

			pTerrainVertices[idx].x = -m_fTerrainScale[0] * (m_iTerrainWidth / 2.0f - j);
			pTerrainVertices[idx].y =  height_map_value * m_fTerrainScale[1];
			pTerrainVertices[idx].z = -m_fTerrainScale[2] * (m_iTerrainHeight / 2.0f - i);

			if( pTerrainVertices[idx].y >Max[1] )
				Max[1] = pTerrainVertices[idx].y;
			if( pTerrainVertices[idx].y < Min[1] )
				Min[1] = pTerrainVertices[idx].y;
		}
	}

	if( m_pHeightMapData != NULL )
		delete[] m_pHeightMapData;

	std::vector<GeometryData> vecMeshes1;
	std::vector<GeometryData> vecMeshes2;
	vecMeshes1.resize(size_textures);
	vecMeshes2.resize(size_textures);

	for( int i = 0; i < size_textures; ++i )
	{
		vecMeshes1[i].pTexture = list_textures[i];
		vecMeshes1[i].numIndices = 0;
		vecMeshes1[i].numVertices = 0;

		vecMeshes2[i].pTexture = list_textures[i];
		vecMeshes2[i].numIndices = 0;
		vecMeshes2[i].numVertices = 0;
	}

	std::vector<GeometryData>* pVecMeshes = NULL;
	int pixmap_idx = -1;
	unsigned char layerOp = 0;

	for( int i = 0; i < grid_height; ++i )
	{
		for( int j = 0; j < grid_width; ++j )
		{
			for( int idx = 0; idx < 2; ++idx )
			{
				if( idx > 0 )
				{
					pixmap_idx = pGridData[i * grid_width + j].nSecondLayer;
					layerOp = pGridData[i * grid_width + j].nSecondLayerOp;
					pVecMeshes = &vecMeshes2;
				}
				else
				{
					pixmap_idx = pGridData[i * grid_width + j].nFirstLayer;
					layerOp = pGridData[i * grid_width + j].nFirstLayerOp;
					pVecMeshes = &vecMeshes1;
				}

				if( pixmap_idx < 0 )
					continue;
				for( int k = 0; k < 4; ++k )
				{
					CUSTOMVERTEX* p = &pTerrainVertices[(i + (k/2)) * m_iTerrainWidth + j + (k % 2)];
					switch(k) 
					{
					case 0:
						p->u = pixmaps[pixmap_idx].left;
						p->v = pixmaps[pixmap_idx].top;
						break;
					case 1:
						p->u = pixmaps[pixmap_idx].right;
						p->v = pixmaps[pixmap_idx].top;
						break;
					case 2:
						p->u = pixmaps[pixmap_idx].left;
						p->v = pixmaps[pixmap_idx].bottom;
						break;
					case 3:
						p->u = pixmaps[pixmap_idx].right;
						p->v = pixmaps[pixmap_idx].bottom;
						break;
					default:
						break;
					}

					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData.push_back(*p);
				}
				(*pVecMeshes)[pixmaps[pixmap_idx].textureId].numVertices = 
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData.size();

				int vertex_index = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].numVertices - 1;

				if( layerOp & 0x01)
				{
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].u = 
						pixmaps[pixmap_idx].left;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].u = 
						pixmaps[pixmap_idx].right;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].u = 
						pixmaps[pixmap_idx].left;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].u = 
						pixmaps[pixmap_idx].right;
				}

				if( layerOp & 0x02)
				{
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].v = 
						pixmaps[pixmap_idx].top;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].v = 
						pixmaps[pixmap_idx].top;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].v = 
						pixmaps[pixmap_idx].bottom;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].v = 
						pixmaps[pixmap_idx].bottom;
				}

				if( layerOp & 0x04)
				{
					float u1 = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].u;
					float v1 = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].v;

					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].u = 
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].u;

					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].u = 
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].u;
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].v = 
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].v;

					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].u = 
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].u;

					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].u = u1;								
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].v = v1;
				}

				if( layerOp & 0x08)
				{
					float u = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].u;
					float v = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].v;

					if( pGridData[i * grid_width + j].IndexOrder == 0)
					{
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].u = 
							(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].u;
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index].v = 
							(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 3].v;
					}
					else
					{
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].u = 
							(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].u;
						(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 1].v = 
							(*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData[vertex_index - 2].v;
					}
				}

				int vert_index = (*pVecMeshes)[pixmaps[pixmap_idx].textureId].vertexData.size() - 4;

				if( pGridData[i * grid_width + j].IndexOrder == 0)
				{
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 2);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 1);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 1);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 2);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 3);
				}
				else
				{
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 2);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 3);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 3);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 1);
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.push_back(
						vert_index + 0);
				}
				(*pVecMeshes)[pixmaps[pixmap_idx].textureId].numIndices = 
					(*pVecMeshes)[pixmaps[pixmap_idx].textureId].indexData.size();
			}
		}
	}	

	delete[] pTerrainVertices;
	delete[] pGridData;	

	MeshPtr pMesh = MeshManager::getSingleton().createManual( strFileName, 
		ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

	static unsigned int index = 0;
	std::vector<GeometryData>::iterator it_begin, it_end;

	for( int i = 0; i < 2; ++i )
	{				
		if( i > 0 )
		{
			it_begin = vecMeshes2.begin();
			it_end = vecMeshes2.end();			
		}
		else
		{
			it_begin = vecMeshes1.begin();
			it_end = vecMeshes1.end();
		}

		while( it_begin != it_end )
		{
			if( it_begin->numVertices < 3 )
			{
				++it_begin;
				continue;
			}
			String materialName = it_begin->pTexture->getName() + StringConverter::toString(index);
			MaterialPtr material = Ogre::MaterialManager::getSingleton().create( materialName, "General", true );
			Ogre::Technique* technique = material->getTechnique(0);

			Ogre::Pass* pass = technique->getPass(0);

			if( i > 0 )
				pass->setSceneBlending( SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA );
			Ogre::TextureUnitState* textureUnitState = pass->createTextureUnitState();
			textureUnitState->setTextureAddressingMode( Ogre::TextureUnitState::TAM_CLAMP );
			textureUnitState->setTextureName( it_begin->pTexture->getName() );
			++index;

			SubMesh* sm = pMesh->createSubMesh();
			sm->useSharedVertices = false;
			sm->vertexData = new VertexData();
			sm->vertexData->vertexStart = 0;
			sm->vertexData->vertexCount = it_begin->numVertices;
			VertexDeclaration* dcl = sm->vertexData->vertexDeclaration;
			size_t offset = 0;
			dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
			offset += VertexElement::getTypeSize(VET_FLOAT3);
			dcl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
			offset += VertexElement::getTypeSize(VET_FLOAT3);
			dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
			offset += VertexElement::getTypeSize(VET_FLOAT2);

			HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
				.createVertexBuffer(
				offset, sm->vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			float* pReal = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));

			for( int j = 0; j < sm->vertexData->vertexCount; j++ )
			{
				*pReal++ = it_begin->vertexData[j].x;
				*pReal++ = it_begin->vertexData[j].y;
				*pReal++ = it_begin->vertexData[j].z;

				*pReal++ = 0.0f;
				*pReal++ = 1.0f;
				*pReal++ = 0.0f;

				*pReal++ = it_begin->vertexData[j].u;
				*pReal++ = it_begin->vertexData[j].v;
			}
			vbuf->unlock();
			sm->vertexData->vertexBufferBinding->setBinding( 0, vbuf);
			sm->indexData->indexCount = it_begin->numIndices;
			sm->indexData->indexBuffer = HardwareBufferManager::getSingleton()
				.createIndexBuffer(HardwareIndexBuffer::IT_32BIT, sm->indexData->indexCount,
				HardwareBuffer::HBU_STATIC_WRITE_ONLY);
			uint32* pI = static_cast<uint32*>(
				sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			for( uint32 j = 0; j < sm->indexData->indexCount; j++ )
			{
				*pI++ = it_begin->indexData[j];
			}

			sm->indexData->indexBuffer->unlock();

			sm->setMaterialName( materialName );

			++it_begin;
		}
	}

	pMesh->_setBounds(AxisAlignedBox( Min[0], Min[1], Min[2], Max[0], Max[1], Max[2]));
	pMesh->_setBoundingSphereRadius(
		std::max( Max[0] - Min[0], std::max(Max[1] - Min[1], Max[2] - Min[2])) / 2.0f );
	pMesh->load();

	Entity* pEntity = m_pSceneManager->createEntity(pMesh->getName());
	pRootNode->attachObject(pEntity);
}

void CTerrainScene::LoadGridInfo( const char* strFileName, void* pGridInfo, unsigned int* pWidth, unsigned int* pHeight )
{
	if( m_pSceneManager == NULL )
		return;

	FILE* pFile = fopen( strFileName, "rb" );

	GridHeader header; 
	fread( &header, sizeof(GridHeader), 1, pFile );

	if( pGridInfo == NULL )
	{
		*pWidth = header.nWidth;
		*pHeight = header.nHeight;
		fclose(pFile);
		return;
	}

	if( *pWidth > header.nWidth || *pHeight > header.nHeight )
	{
		fclose(pFile);
		return;
	}

	char LargeVersion = 0;
	// 看版本号大于这个,就表示后面跟着有个标记用来表示结构体的大小是7字节的版本还是5字节的版本
	if( header.nVersion >= 0x00100001 )
	{
		fread(&LargeVersion , sizeof(LargeVersion), 1, pFile);
	}

	unsigned char byteValue;
	GridInfo* pInfo = (GridInfo*)pGridInfo;
	size_t numGrids = header.nWidth * header.nHeight;
	for(size_t i = 0 ; i < numGrids ; i ++)
	{		
		if( LargeVersion )
		{
			fread(&pInfo->nFirstLayer, sizeof(short), 1, pFile);
			fread(&pInfo->nFirstLayerOp, sizeof(char), 1, pFile);
			fread(&pInfo->nSecondLayer, sizeof(short), 1, pFile);			
		}
		else
		{
			fread(&byteValue, sizeof(char), 1, pFile);
			pInfo->nFirstLayer = byteValue;
			fread(&pInfo->nFirstLayerOp, 1, 1, pFile);						
			fread(&byteValue, sizeof(char), 1, pFile);
			pInfo->nSecondLayer = byteValue;
		}
		fread(&pInfo->nSecondLayerOp, sizeof(char), 1, pFile);
		fread(&pInfo->IndexOrder, sizeof(char), 1, pFile);

		pInfo->nFirstLayer--;
		pInfo->nSecondLayer--;	

		++pInfo;
	}
	fclose(pFile);
}

void CTerrainScene::TraverseBonesAndBuildSceneNodes( Node* pNode, SceneNode* pSceneNode, String suffix, bool bRoot )
{
	Node::ChildNodeIterator pChildNode = pNode->getChildIterator();

	if( bRoot )
		pSceneNode = pSceneNode->createChildSceneNode();
	else
		pSceneNode = static_cast<SceneNode*>(pSceneNode->getParent())->createChildSceneNode();
	pSceneNode->setScale(pNode->getScale());
	pSceneNode->setPosition(pNode->getPosition());
	pSceneNode->setOrientation(pNode->getOrientation());

	pSceneNode = pSceneNode->createChildSceneNode();
	pSceneNode = pSceneNode->createChildSceneNode(pNode->getName() + suffix);

	while( pChildNode.hasMoreElements() )
	{
		Node* pBone = pChildNode.getNext();		
		TraverseBonesAndBuildSceneNodes(pBone, pSceneNode, suffix, false);
	}
}

void CTerrainScene::LoadModelObject( const char* strFileName, SceneNode* pRootNode )
{	
	if( m_pSceneManager == NULL )
		return;

	String FileName = strFileName;
	String FullPath = "";
	{
		ResourceGroupManager::LocationList locates = ResourceGroupManager::getSingleton().getResourceLocationList(
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

		ResourceGroupManager::LocationList::iterator it_begin = locates.begin();
		ResourceGroupManager::LocationList::iterator it_end = locates.end();
		while( it_begin != it_end )
		{		
			FullPath = (*it_begin)->archive->getName() + String("/") + FileName; 
			FILE* pFile = fopen( FullPath.c_str(), "rb" );
			if( pFile != NULL )
			{
				fclose(pFile);
				break;
			}
			++it_begin;
		}
		if(it_begin == it_end)
			return;
	}

	static unsigned int model_count = 0;
	++model_count;
	int name_len = strlen(strFileName);

	const char* p1 = strFileName + name_len;
	const char* p2 = strFileName;
	while( p1 > strFileName )
	{
		if( *p1 == '/' || *p1 == '\\')
		{
			++p1;
			break;
		}
		--p1;
	}
	int interval = p1 - p2;
	String prefix = "";
	if( interval != 1 )
	{
		char* pPrefix = new char[interval + 1];
		memcpy( pPrefix, p2, interval + 1);
		pPrefix[interval] = NULL;
		prefix = pPrefix;
		delete[] pPrefix;
	}
	TiXmlDocument doc;
	doc.LoadFile( FullPath.c_str(), TIXML_ENCODING_UTF8);

	TiXmlElement* pRoot = doc.FirstChildElement("model");
	if( pRoot == NULL )
		return;

	TiXmlElement* pFrameElem = pRoot->FirstChildElement("frame");
	std::vector<String> m_vecRootBoneName;

	if( pFrameElem != NULL )
	{
		const char* pText = pFrameElem->Attribute("name");
		int len = MultiByteToWideChar( CP_UTF8, 0, pText, -1, NULL, 0 );
		wchar_t* pwFileName = new wchar_t[len];
		MultiByteToWideChar( CP_UTF8, 0, pText, -1, pwFileName, len );
		len = WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, NULL, 0, NULL, NULL );
		char* pFileName = new char[len];
		WideCharToMultiByte( CP_ACP, 0, pwFileName, -1, pFileName, len, NULL, NULL );


		SkeletonPtr pSkeleton = SkeletonManager::getSingleton().load(prefix + String(pFileName), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
		unsigned short numAnimation = pSkeleton->getNumAnimations();
		Skeleton::BoneIterator root_bone = pSkeleton->getRootBoneIterator();

		String suffix = StringConverter::toString(model_count);

		while( root_bone.hasMoreElements() )
		{
			Bone* pBone = root_bone.getNext();
			TraverseBonesAndBuildSceneNodes( pBone, pRootNode, suffix );
		}

		for( unsigned short i = 0; i < numAnimation; ++i )
		{
			Animation* pAnim = pSkeleton->getAnimation(i);
			Animation::NodeTrackIterator it = pAnim->getNodeTrackIterator();

			String AnimName = String(pFileName) + StringConverter::toString(model_count);
			Animation* pDestAnim = m_pSceneManager->createAnimation( AnimName, pAnim->getLength() );
			pDestAnim->setInterpolationMode(pAnim->getInterpolationMode());
			AnimationState* pAnimState = m_pSceneManager->createAnimationState(AnimName);
			pAnimState->setLoop(true);
			pAnimState->setEnabled(true);		

			while( it.hasMoreElements() )
			{
				NodeAnimationTrack* pTrack = it.getNext();
				String name = pTrack->getAssociatedNode()->getName();

				SceneNode* pSceneNode = m_pSceneManager->getSceneNode(String(name) + suffix);
				NodeAnimationTrack* pDestTrack = 
					pDestAnim->createNodeTrack(pTrack->getHandle(), pSceneNode->getParent());

				unsigned short numKeyFrames = pTrack->getNumKeyFrames();
				for( unsigned short index = 0; index < numKeyFrames; ++index )
				{
					TransformKeyFrame* keyframe = 
						pDestTrack->createNodeKeyFrame(pTrack->getKeyFrame(index)->getTime()); 
					*keyframe = *(TransformKeyFrame*)(pTrack->getKeyFrame(index));
				}
			}
		}

		delete[]pwFileName;
		delete[]pFileName;
	}
	TiXmlElement* pEntityElem = pRoot->FirstChildElement("entity");
	while( pEntityElem != NULL )
	{
		const char* pUtf8MeshName = pEntityElem->Attribute("mesh");
		const char* pUtf8NodeName = pEntityElem->Attribute("node");
		SceneNode* pSceneNode = NULL;

		if( pUtf8NodeName != NULL )
		{
			int len = MultiByteToWideChar(CP_UTF8, 0, pUtf8NodeName, -1, NULL, 0 );
			wchar_t* pwNodeName = new wchar_t[len];
			MultiByteToWideChar(CP_UTF8, 0, pUtf8NodeName, -1, pwNodeName, len );
			len = WideCharToMultiByte(CP_ACP, 0, pwNodeName, -1, NULL, 0, NULL, NULL );
			char* pNodeName = new char[len];
			WideCharToMultiByte(CP_ACP, 0, pwNodeName, -1, pNodeName, len, NULL, NULL );

			String NodeName = String(pNodeName) + StringConverter::toString(model_count);
			bool bHas = m_pSceneManager->hasSceneNode(NodeName);
			if( bHas )
			{
				pSceneNode = m_pSceneManager->getSceneNode(NodeName);				
			}
			else
				pSceneNode = pRootNode->createChildSceneNode();

			delete[] pwNodeName;
			delete[] pNodeName;
		}
		else
			pSceneNode = pRootNode->createChildSceneNode();

		int len = MultiByteToWideChar(CP_UTF8, 0, pUtf8MeshName, -1, NULL, 0);
		wchar_t* pwMeshName = new wchar_t[len];
		MultiByteToWideChar(CP_UTF8, 0, pUtf8MeshName, -1, pwMeshName, len);
		len = WideCharToMultiByte(CP_ACP, 0, pwMeshName, -1, NULL, 0, NULL, NULL);
		char* pMeshName = new char[len];
		WideCharToMultiByte(CP_ACP, 0, pwMeshName, -1, pMeshName, len, NULL, NULL);

		Entity* pEntity = NULL;
		if( ResourceGroupManager::getSingleton().resourceExists(ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, prefix + String(pMeshName)) )
		{
			pEntity = m_pSceneManager->createEntity( prefix + String(pMeshName));
			pSceneNode->attachObject(pEntity);	
		}

		delete[] pwMeshName;
		delete[] pMeshName;

		if( pEntity != NULL )
		{
			bool bHas = pEntity->hasSkeleton();
			if( bHas )
			{
				bHas = pEntity->getSkeleton()->hasAnimation("[auto]");
				if( bHas )
				{
					AnimationState* pAnimState = pEntity->getAnimationState("[auto]");				
					pAnimState->setLoop( true );
					pAnimState->setEnabled( true );				
					m_AnimationStates.push_back( pAnimState );
				}
			}
		}

		TiXmlElement* pOffset = pEntityElem->FirstChildElement("offset");
		if( pOffset != NULL )
		{
			TiXmlElement* pTranslate = pOffset->FirstChildElement("translate");
			if( pTranslate != NULL )
			{
				const char* pX = pTranslate->Attribute("x");
				const char* pY = pTranslate->Attribute("y");
				const char* pZ = pTranslate->Attribute("z");
				float x = atof(pX);
				float y = atof(pY);
				float z = atof(pZ);

				pSceneNode->translate(x, y, z);				
			}
		}
		pEntityElem = pEntityElem->NextSiblingElement("entity");
	}
}

void CTerrainScene::Update( const FrameEvent& evt )
{
	std::list<AnimationState*>::iterator it_begin = m_AnimationStates.begin();
	std::list<AnimationState*>::iterator it_end = m_AnimationStates.end();

	while( it_begin != it_end )
	{
		(*it_begin)->addTime(evt.timeSinceLastFrame);
		++it_begin;
	}
}

void CTerrainScene::ClearScene()
{
	m_pSceneManager  = NULL;
	m_iTerrainWidth  = 0;
	m_iTerrainHeight = 0;
	m_pHeightMapData = NULL;

	for( int idx = 0; idx < 2; ++idx )
	{
		m_fTerrainScale[idx] = 1.0f;
	}

	m_AnimationStates.clear();
}
原文地址:https://www.cnblogs.com/LinuxHunter/p/1886096.html