Ogre 武侠世界 GridInfo文件格式说明

来源:互联网 发布:淘宝店页头怎么装修 编辑:程序博客网 时间:2024/05/12 05:47
天龙八部的地表做法与多年前的红警2的极为类似。都是由很多个格子(Title)组成,每个格子四个点,两个三角形。
下面我先给出天龙八部GridInfo文件格式,然后再简要介绍一下实现方式。
[GridInfo file format]
DWORD    nVersion    版本号
int    nWidth         地表宽度(横向格子数)
int    nHeight        地表高度(纵向格子数)

如果版本号大于0x00100002则后面跟一个bool型数据,否则不存在这个bool型数据
bool    bLarge        GridInfo是否为7字节类型
如果bLarge存在并且值为1,则其后跟的是7字节版本否则为5字节版本


[GridInfo 5字节版本]

BYTE    nFirstLayer    该值即为pixelmap的索引(第几个pixelmap)
BYTE    nFirstLayerOp    对nFirstLayer的操作,可能取值如下:
0 不变
1 水平翻转
2 垂直翻转
4 向左旋转90度
8 对角线镜像
注意:这些值之间是可以取和的,比如9=1+8说明图片需要水平翻转和对角线镜像

BYTE    nSecondLayer    该值为pixelmap的索引
天龙八部的地表最多可以两层融合,说白了就是每个点里有两层UV,这里为第二层pixelmap的索引
BYTE    nSecondLayerOp    对nSecondLayer的操作,取值同nFirstLayerOp
BYTE    IndexOrder    对格子的三角形的操作,可能取值如下
0正常三角形索引
1不同于正常的三角形索引
如下图,该值主要用在水池啊一类的地方,如果三角形索引不变的话,水池四个角中的两个角就不对了。



本文出自www.MobileGameBase.com
[GridInfo 7字节版本]
short    nFirstLayer
读取后需交换高8位与低8位的值,需做如下操作
nFirstLayer = (nFirstLayer<<8)|(nFirstLayer>>8)

BYTE    nFirstLayerOp

short    nSecondLayer
同nFirstLayer,需交换高8位与低8位的值
BYTE    nSecondLayerOp
BYTE    IndexOrder


想象一下如果你设好每个点的位置,UV,法线,材质,整个场景不就出来了嘛。

现在的问题是如何操作这些VertexData和IndexData,其实Ogre本身就有大量的类直接这两者,比如Mesh,StaticGeometry,ManualObject等等。


部分源码:

使用的是Ogre的资源管理器来读取,另提供了saveToXML和saveToTGA的功能保存到XML文件和TGA文件:

GridInfos.h#pragma oncenamespace 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();    }};

转载自:

http://www.mobilegamebase.com/

http://www.cppblog.com/mybios/archive/2009/07/26/91267.html