zoukankan      html  css  js  c++  java
  • 不通过Content直接创建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(00, 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~

  • 相关阅读:
    App调试的几个命令实践【转】
    解决sdk更新时候报错 http://dl-ssl.google.com/android上不去,链接拒绝
    fastjson序列化排序问题
    Java中的四种引用
    equal&==&hashcode
    ThreadPool线程池的关注点
    JVM的本地方法栈
    JVM的堆分配
    JVM的类装载子系统
    JVM的数据类型
  • 原文地址:https://www.cnblogs.com/huobilie/p/2112244.html
Copyright © 2011-2022 走看看