生成Xnb文件

好久没关注Xna了,刚刚上了Xna游戏世界 得知AppHub发布了新示例,其中有关于XNB文件结构解析的示例,于是第一时间去浏览了下:Compiled (XNB) Content Format 。有兴趣的朋友可以下载示例研究一下(是C++代码),另外里面有份关于XNB文件结构的文档比较好。

参照文档,我用C#(4.0)写了个简单的纹理XNB文件的生成工具。其实就是个命令行工具,把一堆文件拖上去,会自动将图像文件编译到相同目录下。编译后的文件放到游戏的Content目录中,然后Content.Load<Texture2D>就能加载到Texture2D变量中用于绘制。

 

1   static   void  Main( string [] args)
 2           {
 3                foreach  ( string  fileName  in  args)
 4               {
 5                    if  (File.Exists(fileName))
 6                       ImageToXnb(fileName);
 7               }
 8               Console.ReadLine();
 9           }
10  
11            static   void  ImageToXnb( string  fileName)
12           {
13                try
14               {
15                   Bitmap image  =  Bitmap.FromFile(fileName)  as  Bitmap;
16                    if  (image  !=   null )
17                   {
18                        //   获取图像的数组。
19                        int  w  =  image.Width;
20                        int  h  =  image.Height;
21                        int  s  =   4   *  w  *  h;
22                       BitmapData bmpData  =  image.LockBits( new  Rectangle( 0 0 , w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
23                        byte [] bmpBytes  =   new   byte [s];
24                        unsafe
25                       {
26                            byte *  data  =  ( byte * )(bmpData.Scan0.ToPointer());
27                            for  ( int  i  =   0 ; i  <  w  *  h; i ++ )
28                           {
29                               bmpBytes[ 4   *  i]  =  data[ 4   *  i  +   2 ];
30                               bmpBytes[ 4   *  i  +   1 =  data[ 4   *  i  +   1 ];
31                               bmpBytes[ 4   *  i  +   2 =  data[ 4   *  i];
32                               bmpBytes[ 4   *  i  +   3 =  data[ 4   *  i  +   3 ];
33                           }
34                       }
35                       image.UnlockBits(bmpData);
36                        //   开始写入xnb数据。
37                       List < byte >  bytes;
38                        string  xnbFile  =  Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName)  +   " .xnb " );
39                       FileStream stream  =   new  FileStream(xnbFile, FileMode.Create, FileAccess.Write);
40                       bytes  =   new  List < byte > ();
41                       bytes.AddRange(Encoding.Default.GetBytes( " XNB " ));    //  文件头标识"XNB"
42                       bytes.AddRange(Encoding.Default.GetBytes( " w " ));      //  平台标识:w - Window
43                       bytes.Add(( byte ) 5 );      //  5 - Xna4.0
44                        //   写入当前xnb文件需要的Type Reader。Texture2D对应的是Texture2DReader。
45                       bytes.Add(( byte ) 1 );      //  标记位:0x01 - 是否HiDef模式;0x80 - 是否压缩。
46                       bytes.Add(( byte ) 1 );      //  Type Reader的数量。
47                        //   写入Type Reader的全称。
48                        string  reader  =   " Microsoft.Xna.Framework.Content.Texture2DReader, Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553 " ;
49                       bytes.Add(( byte )reader.Length);
50                       bytes.Add(( byte ) 1 );
51                       bytes.AddRange(Encoding.Default.GetBytes(reader));
52                       bytes.Add(( byte ) 0 );
53                       bytes.AddRange(BitConverter.GetBytes( 0 ));    //  Type Reader 的版本。
54                        //   写入xnb文件的内容。
55                       bytes.Add(( byte ) 1 );      //  内容的数量。
56                        //   写入内容,此处为Texture2D。
57                       bytes.AddRange(BitConverter.GetBytes( 0 ));    //  Surface format-此处为Color。
58                       bytes.AddRange(BitConverter.GetBytes(( uint )w));      //  宽和高。
59                       bytes.AddRange(BitConverter.GetBytes(( uint )h));
60                       bytes.AddRange(BitConverter.GetBytes(( uint ) 1 ));      //  Mip 数量。
61                       bytes.AddRange(BitConverter.GetBytes(( uint )(s)));    //  数据大小。
62                       bytes.AddRange(bmpBytes);
63                        //   计算文件大小,插入指定位置。实际上在那个标志位后面紧跟着就是 uint 类型的文件大小。
64                        int  size  =  bytes.Count  +   4 ;
65                       bytes.InsertRange( 6 , BitConverter.GetBytes(size));
66                        //   写入文件。
67                       stream.Write(bytes.ToArray(),  0 , bytes.Count);
68                       stream.Close();
69                       Console.WriteLine( " 文件 {0} 成功编译成 xnb 文件! " , fileName);
70                   }
71               }
72                catch
73               {
74                   Console.WriteLine( " 文件 {0} 不是有效的图像文件,编译失败! " , fileName);
75               }
76           }

这里有几点说明下:

1、代码用到不安全代码,要在项目属性中把“允许不安全代码”勾上。

2、Texture2DReader类型的全称是从已生成的XNB文件中复制过来的,我在对象浏览器中都没找到这个类,有人能告诉我为什么吗?

3、因为文件中第7个Byte开始的Uint类型的数表示文件大小,所以我先把整个文件写到List<byte>中,然后将数组长度加上4作为文件大小插入到该位置,然后在将整个List一起保存。(事实上开始的时候我把文件大小都设为0,游戏一样可以正常加载)

4、如果标记位指定文件为压缩的,那么文件大小后面还需指定解压后的文件大小,因为对压缩不甚了解,所以直接跳过了。

5、这里设置纹理的Surface format为Color,这种格式最占空间了,拿一张约900kb的jpg图像编译后达3M多。所以要将本程序实用化,可以研究下其他的格式。

结束,睡觉zzzzz~

转自:http://www.cnblogs.com/huobilie/archive/2011/07/20/2112244.html

你可能感兴趣的:(文件)