天龙八部GridInfo文件的格式已经有人公布了,在这里: http://www.mobilegamebase.com/blog/article.asp?id=17
不过,此文中有点笔误的地方,就是那个nFirstLayerOP的位标记的描述有点错误,正确的应该如下:
// 图片水平翻转,即左右翻转
#define FLIP_HORIZINTAL 1
// 图片垂直翻转,即上下翻转
#define FLIP_VERTICAL 2
// 逆时针旋转90度
#define ANTICLOCKWISE_90 4
// 以三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则把右上的坐标复制到左下
#define FLIP_DIAGONAL 8
具体的读取源码如下,使用的是Ogre的资源管理器来读取,另提供了saveToXML和saveToTGA的功能保存到XML文件和TGA文件:
GridInfos.h
#pragma once
namespace Ogre
{
struct GridHeader
{
DWORD nMagic;
// 版本号
DWORD nVersion;
// 地表宽度(横向格子数)
int nWidth;
// 地表高度(纵向格子数)
int nHeight;
};
// 图片水平翻转,即左右翻转
#define FLIP_HORIZINTAL 1
// 图片垂直翻转,即上下翻转
#define FLIP_VERTICAL 2
// 逆时针旋转90度
#define ANTICLOCKWISE_90 4
// 以三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则把右上的坐标复制到左下
#define FLIP_DIAGONAL 8
// 单个网格信息
struct GridInfo
{
// 该值即为pixelmap的索引(第几个pixelmap)
short nFirstLayer;
// 对nFirstLayer的操作,取值是上面几个定义的宏,可以互相组合
BYTE nFirstLayerOp;
// 该值为pixelmap的索引
// 天龙八部的地表最多可以两层融合,说白了就是每个点里有两层UV,这里为第二层pixelmap的索引
short nSecondLayer;
// 对nSecondLayer的操作,取值同nFirstLayerOp
BYTE nSecondLayerOp;
// 对格子的三角形的操作,可能取值如下
// 0正常三角形索引
// 1不同于正常的三角形索引
BYTE IndexOrder;
};
// 整个地形的网格信息
class GridInfos
{
public :
GridInfos( void );
virtual ~ GridInfos( void );
// 打开网格文件
void open( const String & fileName , const String & groupName);
// 保存到XML文件中
void saveToXML( const String & xmlFileName);
// 保存到TGA文件中
void saveToTGA( const String & tgaFileName);
// 完毕并清空网格
void close();
typedef std::vector < GridInfo > GridData;
// 网格信息数组
GridData m_data;
// 宽高
size_t m_width , m_height;
};
};
namespace Ogre
{
struct GridHeader
{
DWORD nMagic;
// 版本号
DWORD nVersion;
// 地表宽度(横向格子数)
int nWidth;
// 地表高度(纵向格子数)
int nHeight;
};
// 图片水平翻转,即左右翻转
#define FLIP_HORIZINTAL 1
// 图片垂直翻转,即上下翻转
#define FLIP_VERTICAL 2
// 逆时针旋转90度
#define ANTICLOCKWISE_90 4
// 以三角形的对角线镜像,IndexOrder==0时就把左上的纹理坐标复制到右下,否则把右上的坐标复制到左下
#define FLIP_DIAGONAL 8
// 单个网格信息
struct GridInfo
{
// 该值即为pixelmap的索引(第几个pixelmap)
short nFirstLayer;
// 对nFirstLayer的操作,取值是上面几个定义的宏,可以互相组合
BYTE nFirstLayerOp;
// 该值为pixelmap的索引
// 天龙八部的地表最多可以两层融合,说白了就是每个点里有两层UV,这里为第二层pixelmap的索引
short nSecondLayer;
// 对nSecondLayer的操作,取值同nFirstLayerOp
BYTE nSecondLayerOp;
// 对格子的三角形的操作,可能取值如下
// 0正常三角形索引
// 1不同于正常的三角形索引
BYTE IndexOrder;
};
// 整个地形的网格信息
class GridInfos
{
public :
GridInfos( void );
virtual ~ GridInfos( void );
// 打开网格文件
void open( const String & fileName , const String & groupName);
// 保存到XML文件中
void saveToXML( const String & xmlFileName);
// 保存到TGA文件中
void saveToTGA( const String & tgaFileName);
// 完毕并清空网格
void close();
typedef std::vector < GridInfo > GridData;
// 网格信息数组
GridData m_data;
// 宽高
size_t m_width , m_height;
};
};
GridInfos.cpp
#include
"
GridInfos.h
"
namespace Ogre
{
GridInfos::GridInfos( void )
: m_width( 0 )
, m_height( 0 )
{
}
GridInfos:: ~ GridInfos( void )
{
close();
}
// 打开网格文件
void GridInfos::open( const String & fileName , const String & groupName)
{
DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource(fileName , groupName);
if (stream.isNull())
{
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
" 打开地形网格文件失败: " + fileName,
" GridInfos::open " );
return ;
}
GridHeader header;
// 读取文件头
stream -> read( & header , sizeof (header));
m_width = header.nWidth;
m_height = header.nHeight;
bool largeVersion = false ;
// 看版本号大于这个,就表示后面跟着有个标记用来表示结构体的大小是7字节的版本还是5字节的版本
if (header.nVersion >= 0x00100001 )
{
stream -> read( & largeVersion , sizeof (largeVersion));
}
size_t uCount = m_width * m_height;
m_data.resize(uCount);
BYTE byteValue;
for (size_t i = 0 ; i < uCount ; i ++ )
{
GridInfo & info = m_data[i];
if (largeVersion)
{
stream -> read( & info.nFirstLayer , 2 );
}
else
{
stream -> read( & byteValue , 1 );
info.nFirstLayer = byteValue;
}
info.nFirstLayer -- ;
stream -> read( & info.nFirstLayerOp , 1 );
if (largeVersion)
{
stream -> read( & info.nSecondLayer , 2 );
}
else
{
stream -> read( & byteValue , 1 );
info.nSecondLayer = byteValue;
}
info.nSecondLayer -- ;
stream -> read( & info.nSecondLayerOp , 1 );
stream -> read( & info.IndexOrder , 1 );
}
// saveToXML(fileName + ".xml");
}
// 完毕并清空网格
void GridInfos::close()
{
m_width = m_height = 0 ;
m_data.clear();
}
// 保存到TGA文件中
void GridInfos::saveToTGA( const String & tgaFileName)
{
size_t uCount = m_width * m_height;
RGBA * rgb = new RGBA[uCount];
for (size_t i = 0 ; i < uCount ; i ++ )
{
rgb[i] = (( ulong )m_data[i].nFirstLayer << 16l ) | ( ulong )m_data[i].nSecondLayer;
}
Image image;
image.loadDynamicImage((uchar * )rgb , m_width , m_height , 1 , PF_A8R8G8B8);
image.save(tgaFileName);
}
// 保存到XML文件中
void GridInfos::saveToXML( const String & xmlFileName)
{
std::ofstream stream;
stream.open(xmlFileName.c_str());
stream << " <Grids> " << std::endl;
for (size_t i = 0 ; i < m_data.size() ; i ++ )
{
GridInfo & info = m_data[i];
stream << " <Grid x= " << i % m_width
<< " z= " << i / m_width
<< " FirstLayer= " << ( int )info.nFirstLayer
<< " FirstLayerOp= " << ( int )info.nFirstLayerOp
<< " SecondLayer= " << ( int )info.nSecondLayer
<< " SecondLayerOp= " << ( int )info.nSecondLayerOp
<< " IndexOrder= " << ( int )info.IndexOrder
<< " /> "
<< std::endl
;
}
stream << " </Grids> " << std::endl;
stream.close();
}
};
namespace Ogre
{
GridInfos::GridInfos( void )
: m_width( 0 )
, m_height( 0 )
{
}
GridInfos:: ~ GridInfos( void )
{
close();
}
// 打开网格文件
void GridInfos::open( const String & fileName , const String & groupName)
{
DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource(fileName , groupName);
if (stream.isNull())
{
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
" 打开地形网格文件失败: " + fileName,
" GridInfos::open " );
return ;
}
GridHeader header;
// 读取文件头
stream -> read( & header , sizeof (header));
m_width = header.nWidth;
m_height = header.nHeight;
bool largeVersion = false ;
// 看版本号大于这个,就表示后面跟着有个标记用来表示结构体的大小是7字节的版本还是5字节的版本
if (header.nVersion >= 0x00100001 )
{
stream -> read( & largeVersion , sizeof (largeVersion));
}
size_t uCount = m_width * m_height;
m_data.resize(uCount);
BYTE byteValue;
for (size_t i = 0 ; i < uCount ; i ++ )
{
GridInfo & info = m_data[i];
if (largeVersion)
{
stream -> read( & info.nFirstLayer , 2 );
}
else
{
stream -> read( & byteValue , 1 );
info.nFirstLayer = byteValue;
}
info.nFirstLayer -- ;
stream -> read( & info.nFirstLayerOp , 1 );
if (largeVersion)
{
stream -> read( & info.nSecondLayer , 2 );
}
else
{
stream -> read( & byteValue , 1 );
info.nSecondLayer = byteValue;
}
info.nSecondLayer -- ;
stream -> read( & info.nSecondLayerOp , 1 );
stream -> read( & info.IndexOrder , 1 );
}
// saveToXML(fileName + ".xml");
}
// 完毕并清空网格
void GridInfos::close()
{
m_width = m_height = 0 ;
m_data.clear();
}
// 保存到TGA文件中
void GridInfos::saveToTGA( const String & tgaFileName)
{
size_t uCount = m_width * m_height;
RGBA * rgb = new RGBA[uCount];
for (size_t i = 0 ; i < uCount ; i ++ )
{
rgb[i] = (( ulong )m_data[i].nFirstLayer << 16l ) | ( ulong )m_data[i].nSecondLayer;
}
Image image;
image.loadDynamicImage((uchar * )rgb , m_width , m_height , 1 , PF_A8R8G8B8);
image.save(tgaFileName);
}
// 保存到XML文件中
void GridInfos::saveToXML( const String & xmlFileName)
{
std::ofstream stream;
stream.open(xmlFileName.c_str());
stream << " <Grids> " << std::endl;
for (size_t i = 0 ; i < m_data.size() ; i ++ )
{
GridInfo & info = m_data[i];
stream << " <Grid x= " << i % m_width
<< " z= " << i / m_width
<< " FirstLayer= " << ( int )info.nFirstLayer
<< " FirstLayerOp= " << ( int )info.nFirstLayerOp
<< " SecondLayer= " << ( int )info.nSecondLayer
<< " SecondLayerOp= " << ( int )info.nSecondLayerOp
<< " IndexOrder= " << ( int )info.IndexOrder
<< " /> "
<< std::endl
;
}
stream << " </Grids> " << std::endl;
stream.close();
}
};