生成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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM