程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> VirtuaNES.v0.97源碼探究<3> 卷軸查看器

VirtuaNES.v0.97源碼探究<3> 卷軸查看器

編輯:關於C語言

啟動NES模擬器,再一次打開我們經典的超級馬裡奧1。

選擇工具->查看器->卷軸查看器。這次會出現如下的一個窗口。

141725196.png


響應函數依舊是

WNDCMD CMainFrame::OnViewCommand( WNDCMDPARAM )

這方面的內容上節說過就不說了。


這次進入的是第二個分支

case    ID_VIEW_NAMETABLE:
            if( !m_NameTableView.m_hWnd ) {
                m_NameTableView.Create( HWND_DESKTOP );
            }
            ::SetWindowPos( m_NameTableView.m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
            break;


直接介紹m_NameTableView所屬的類。


CNameTableView

所在文件 Source Files/NameTableView.cpp Header Files/NameTableView.h


可以看到CNameTableView和CPatternView不論是類成員的組成,還是成員函數,都是大同小異的,因此下面我只挑不同的講,有什麼疑問看上節就好了。


位圖信息頭:

m_BitmapHdr.bih.biSize        = sizeof(BITMAPINFOHEADER);
m_BitmapHdr.bih.biWidth       = 512;
m_BitmapHdr.bih.biHeight      = -480;
m_BitmapHdr.bih.biPlanes      = 1;
m_BitmapHdr.bih.biBitCount    = 8;
m_BitmapHdr.bih.biCompression = BI_RGB;
m_BitmapHdr.bih.biClrUsed     = 16;


可以知道顯示在窗口上的位圖寬512像素,高480像素。


512*480有什麼特殊含義嗎?有!

NES中有4個命名表和屬性表的組合。1個組合就可以在屏幕上顯示出一幅畫面了。

試著將512*480除以4,得到256*240。NES游戲畫面的分辨率正好是256*24032*30個tile組成畫面,tile是8*8像素的,由此求得)。

這樣就可以推斷出,顯示在卷軸查看器上的是4幅游戲背景。


至於NES中為何有4個命名表和屬性表的組合,這暫時還不必深入研究其實是博主我自己也還不懂)。


接下來深入講解OnTimer函數。


for( INT i = 0; i < 16; i++ ) {
        m_BitmapHdr.rgb[i] = m_Palette[BGPAL[i]];
    }


讀取背景的16個顏色。


for( INT n = 0; n < 4; n++ ) {
        LPBYTE  lpVRAM = PPU_MEM_BANK[8+n];
        LPBYTE  lpScnv = &m_lpPattern[(n>>1)*512*240+(n&1)*256];
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
        for( INT y = 0; y < 30; y++ ) {
            for( INT x = 0; x < 32; x++ ) {
                INT tile = lpVRAM[x+y*32]*16+((PPUREG[0]&PPU_BGTBL_BIT)<<8);
                BYTE    attr = ((lpVRAM[0x03C0+(x/4)+(y>>2)*8]>>((x&2)+(y&2)*2))&3)<<2;
                LPBYTE  lpScn = &lpScnv[x*8+y*8*512];
                LPBYTE  lpPtn = &PPU_MEM_BANK[tile>>10][tile&0x03FF];
                for( INT p = 0; p < 8; p++ ) {
                    BYTE    chr_l = lpPtn[p];
                    BYTE    chr_h = lpPtn[p+8];
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
                    lpScn[0] = ((chr_h>>6)&2)|((chr_l>>7)&1)|attr;
                    lpScn[4] = ((chr_h>>2)&2)|((chr_l>>3)&1)|attr;
                    lpScn[1] = ((chr_h>>5)&2)|((chr_l>>6)&1)|attr;
                    lpScn[5] = ((chr_h>>1)&2)|((chr_l>>2)&1)|attr;
                    lpScn[2] = ((chr_h>>4)&2)|((chr_l>>5)&1)|attr;
                    lpScn[6] = ((chr_h>>0)&2)|((chr_l>>1)&1)|attr;
                    lpScn[3] = ((chr_h>>3)&2)|((chr_l>>4)&1)|attr;
                    lpScn[7] = ((chr_h<<1)&2)|((chr_l>>0)&1)|attr;
                    // Next line
                    lpScn+=512;
                }
            }
        }
    }


第1行 從左到右依次畫4幅游戲背景。

第2行 上節已經講過PPU_MEM_BANK的後四個字節指針是指向四個命名表和屬性表。因此lpVRAM指向第n個命名表和屬 性表。

第3行 第n幅背景的首像素的地址。

第5-6行 30,32兩個數字大家不陌生了吧,分別是縱向和橫向的tile數。

第7-8行 如果把PPU_MEM_BANK看成大小為12*1K的連續空間在真機,也就是FC家用機中,這塊地址空間就是連續的),那麼這個式子求出的結果就是tile的地址。不過由於這裡把地址空間給分成了12份,因此求得的值10~13位是PPU_MEM_BANK數組的下標,0~9位是1K空間中的偏移量。

式子每部分的含義,再介紹一下。

lpVRAM[x+y*32]是tile的編號。一個tile在圖案表中占16個字節,因此lpVRAM[x+y*32]*16是該tile在圖案表中的偏移地址。

PPUREG[0]是一個IO端口,長16位,每一位都有特定含義。具體每一位什麼含義可先不管,只需知道第4位表示當前使用的圖案表的地址。該位為0,使用0x0000的圖案表,該位為1,使用0x1000的圖案表。(PPUREG[0]&PPU_BGTBL_BIT)<<8這個式子就是用來求得0x0000或0x1000。

第9-10行 求得的是每一個tile對應的高兩位數據。attr第2,3位存放求得的數據,其余位為0之所以這麼保存,是為了後面求算方便)。

第11行 tile的起始屏幕指針。

第12行 從圖案表讀取1個tile所有像素的低2位,共16個字節。

第13行 正式開始畫tile,每次循環畫1行。

第14-15行 之前提到過,2個字節,第1個字節是像素的第0位,第2個字節是像素的第1位。

第17-24行 在求每一個像素。有了前面的基礎,這些個式子應該很容易看懂。

第26行 指向tile的下一行的起始位置。

本文出自 “三人乘虎” 博客,請務必保留此出處http://darhx.blog.51cto.com/7920146/1303236

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved