金庸群侠传资源压缩数据结构研究

金庸群侠传是智冠科技90年代出品的精品DOS游戏,

 

其资源压缩包格式紧凑而科学,这里我们一起学习一下其数据结构。并且编写一个能够读取解析它的程序,

 

 

 

以下是我对 Hdgrp资源文件解包的运行结果展示

 


金庸群侠传资源压缩数据结构研究

 

下面我们看一下资源类型:

 

其资源包括 idx和grp文件,idx记录了各个资源的索引、grp(group pictures?)存储了具体数据。

 

另外以Mmap.col作为整体的调色板,存储各种颜色数据。

 

idx文件每4个byte为一个section,每个section记录一个资源图片的endoffset,即又是下一个资源图片的startoffset。

 

----------

int32  |  endoffset

 

grp文件,以idx文件为基准,按offset区间划分存储图片,每个图片资源:

 

---------

int16 | w

int16 | h

int16 | x (不知道有什么用)

int16 | y(不知道有什么用)

以下h行,每行支持多个section,每个section数据结构

----------

int8 | 该行字节数

[section]

int8 | t 透明像素点个数

int8 | nt 非透明像素点个数

nt * int8 | 该点对应调色板数据,如1,则对应调色板第一个颜色值

 

 

调色板文件Mmap.col

一共256*3 byte,256色,每个颜色按rgb 除以4存放,按顺序存放

----------

byte | r

byte | g

byte | b

 

这样就可以解每个资源文件了。下面是部分核心的C#代码,我使用WPF的bitmapimage进行渲染。

 

 

 

 

 

    class GameResource
    {
        #region 单例
        static public GameResource Instance
        {
            get
            {
                if(_instance==null){
                    _instance = new GameResource();    
                }
                return _instance;
            }
        }

        static GameResource _instance = null;
        private GameResource()
        {
            ImageFiles = new Dictionary<string, List<Image>>();
        }
        #endregion

        public Dictionary<string, List<Image>> ImageFiles;
    }

    .............
        /// <summary>
        /// 初始化调色板
        /// </summary>
        public void InitColors() 
        {
            FileStream f = new FileStream("data/Mmap.col", FileMode.Open);
            BinaryReader reader = new BinaryReader(f);
            for (int i = 0; i < 256; ++i)
            {
                byte[] color = reader.ReadBytes(3);
                for (int j = 0; j < color.Length; ++j)
                {
                    color[j] = (byte)((int)color[j] * 4);
                }
                colorMap[i] = color;
            }
            reader.Close();
            f.Close();
        }

        Dictionary<int, byte[]> colorMap = new Dictionary<int, byte[]>();

        private BitmapImage ReadImage(BinaryReader reader, int length)
        {
            int w = reader.ReadInt16();
            int h = reader.ReadInt16();
            int x = reader.ReadInt16();
            int y = reader.ReadInt16();

            List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>();
            colors.Add(System.Windows.Media.Colors.Blue);
            colors.Add(System.Windows.Media.Colors.Green);
            colors.Add(System.Windows.Media.Colors.Red);
            
            BitmapPalette palette = new BitmapPalette(colors);
            PixelFormat pf = PixelFormats.Bgra32;

            int stride = (w * pf.BitsPerPixel + 7) / 8;
            byte[] pixels = new byte[h * stride];
            for (int i = 0; i < pixels.Length; ++i)
            {
                pixels[i] = 0x00;
            }
            int p = 0;
            try
            {
                for (int i = 0; i < h; ++i) //H行
                {
                    p = i * w * pf.BitsPerPixel / 8;
                    int count = reader.ReadByte(); //该行字节数
                    int offset = 0;

                    while (offset < count)
                    {
                        int transparentPixs = reader.ReadByte(); //透明像素个数
                        offset++;
                        p += transparentPixs * pf.BitsPerPixel / 8;
                        int nonTransPix = reader.ReadByte(); //非透明像素个数
                        offset++;
                        for (int j = 0; j < nonTransPix; ++j)
                        {
                            int colorKey = reader.ReadByte();

                            pixels[p] = colorMap[colorKey][2]; //b
                            p++;
                            pixels[p] = colorMap[colorKey][1]; //g
                            p++;
                            pixels[p] = colorMap[colorKey][0]; //r
                            p++;
                            pixels[p] = 0xFF; //a
                            p++;

                            offset++;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(p.ToString());
            }
            
            BitmapSource image = BitmapSource.Create(
                w,
                h,
                96,
                96,
                pf,
                palette,
                pixels,
                stride);
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            
            MemoryStream memoryStream = new MemoryStream();
            BitmapImage bImg = new BitmapImage();
            encoder.Frames.Add(BitmapFrame.Create(image));
            encoder.Save(memoryStream);

            bImg.BeginInit();
            bImg.StreamSource = new MemoryStream(memoryStream.ToArray());
            bImg.EndInit();

            memoryStream.Close();
            return bImg;
        }

        public List<Image> LoadImages(string filename)
        {
            List<Image> rst = new List<Image>();
            FileStream f = new FileStream(filename + ".idx", FileMode.Open);
            BinaryReader reader = new BinaryReader(f);

            FileStream gf = new FileStream(filename + ".grp", FileMode.Open);
            BinaryReader greader = new BinaryReader(gf);
            try
            {
                int startOffset = 0;
                while (f.CanRead)
                {
                    int endOffset = reader.ReadInt32();
                    Image image = new Image();
                    image.Source = ReadImage(greader, endOffset-startOffset);
                    rst.Add(image);
                    startOffset = endOffset;
                }
            }
            catch (Exception e)
            {

            }
            greader.Close();
            gf.Close();
            reader.Close();
            f.Close();
            return rst;
        }

        public void LoadResource(string filename)
        {
            GameResource.Instance.ImageFiles.Add(filename, LoadImages(filename));
        }

..................
 

 

 

 

 

你可能感兴趣的:(数据结构)