#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(); }