转自:http://www.cppblog.com/mybios/archive/2008/03/09/44046.aspx
天龙八部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;

    };

};

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


};