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