Feb 6

FSH文件與DXT解碼

Lrdcq , 2015/02/06 23:10 , 程序 , 閱讀(2363) , Via 本站原創
SC4中使用了大量的FSH格式文件作為貼圖素材,這是一種屬￿EA私有的貼圖格式。
不過經過大量的努力,我們獲取到FSH文件格式分析結果,並且除了FSH私有head和entry以外,貼圖的主要內容事實上是DXT1或者DXT3壓縮格式的數據(當然,也有可能是16/24/32位RGB或者8位查表數據,但不常用)

於是,我們開FSH的關鍵,在於解析FSHhead與entry的格式,還有就是DXT壓縮解碼。

FSH的頭部部分是如下構成:
點擊在新視窗中瀏覽此圖片

很簡單的結構,下面緊接著就是entry列表(話說,也就是說一個FSH
點擊在新視窗中瀏覽此圖片

entry列表裡的每個entry更是簡單,只有一個固定DWORD的name和具體數據是offset
而看到具體數據,第一個是個flag表示數據的壓縮/儲存方式+預留,再下面是圖像大小和一些使用顯示相關的數據,對於解析圖片數據無視無視啦

然後看到DXT的壓縮格式。我們需要使用的是DXT1和DXT3格式,而DXT3格式只是DXT1每個區塊上面加上8byte的透明度數據,所以可以一概而論。每個4x4的壓縮區塊,原本64個byte的數據壓縮為8個byte或者16個byte出來的結構如下:
點擊在新視窗中瀏覽此圖片

上面16位的alpha數據大家心知肚明瞭,看下面。
首先是565的16位RGB數據color1和color2,作為關鍵顏色1和2,另外,我們通過這兩個顏色的線性插值算出另外兩個關鍵顏色3和4,算法如下:
var c1=f.read('Uint');
var c2=f.read('Uint');
var c_l=[];
c_l[0]=[n((c1&0xF800)>>11,32,256),n((c1&0x07E0)>>5,64,256),n((c1&0x001F),32,256)];
c_l[1]=[n((c2&0xF800)>>11,32,256),n((c2&0x07E0)>>5,64,256),n((c2&0x001F),32,256)];
if(c1>c2){
  c_l[2]=[c_l[0][0]*2/3+c_l[1][0]/3,c_l[0][1]*2/3+c_l[1][1]/3,c_l[0][2]*2/3+c_l[1][2]/3];
  c_l[3]=[c_l[1][0]*2/3+c_l[0][0]/3,c_l[1][1]*2/3+c_l[0][1]/3,c_l[1][2]*2/3+c_l[0][2]/3];
}else{
  c_l[2]=[c_l[0][0]/2+c_l[1][0]/2,c_l[0][1]/2+c_l[1][1]/2,c_l[0][2]/2+c_l[1][2]/2];
  c_l[3]=[0,0,0];
}


所以,這四個顏色就是這個4x4區域的顏色表,整個區域16個像素被壓縮到4個相近的顏色。而下面那16個2位數據就是16個像素的索引目錄——這樣解釋一目了然了吧。

因此整個DXT數據解析的關鍵是計算出4個關鍵顏色,並找出顏色對應在像素中的位置即可。DXT部分整段代碼如下:

完整的代碼可以參看如下示例:
http://lrdcq.com/test/sc4reader/example/FSH_test.html
(請打開一個DXT1或者DXT3壓縮的FSH文件,提交即可輸出出其中所有圖片)

另外說一句,FSH使用DXT這種壓縮率極低的圖像封裝格式顯然是為了可以直接將圖像數據不經處理直接壓入顯卡通道中,同時也想保持自定義格式的可用性與豐富性,可謂平衡程序性能的權益之舉。
logo