VirtuaNES. v0.97 source code Exploration & lt; 2 & gt; graphic viewer

Source: Internet
Author: User

Start the NES simulator and open our classic super Mario 1.

Choose tool> viewer> graphic viewer. The following window is displayed.

650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/194U64L0-0.png "title =" Capture. PNG "alt =" 141431758.png"/>

Click in the window, and the screen will change.

What is the significance of these images? How does the VirtiaNES simulator display these images?

The above questions are the topic of this blog.


Response Functions

The response function of the menu option "graphic viewer" is:

WNDCMD CMainFrame: OnViewCommand (wnd1_param)

Source Files \ MainFrame. cpp

The search function of VS series IDE should be relatively powerful. I will not talk about the specific line of the function. The code for this response function is as follows:

WNDCMD  CMainFrame::OnViewCommand( WNDCMDPARAM ){    if( !Emu.IsRunning() || !Nes )        return;    switch( uID ) {        case    ID_VIEW_PATTERN:            if( !m_PatternView.m_hWnd ) {                m_PatternView.Create( HWND_DESKTOP );            }            ::SetWindowPos( m_PatternView.m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );            break;        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;        case    ID_VIEW_PALETTE:            if( !m_PaletteView.m_hWnd ) {                m_PaletteView.Create( HWND_DESKTOP );            }            ::SetWindowPos( m_PaletteView.m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );            break;        case    ID_VIEW_MEMORY:            if( !m_MemoryView.m_hWnd ) {                m_MemoryView.Create( HWND_DESKTOP );            }            ::SetWindowPos( m_MemoryView.m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );            break;        default:            break;    }}

Row 3: The function parameter wnd1_param is a macro definition, which is actually HWND hWnd, UINT uID

HWnd is the handle of the parent window, that is, the main interface. UID is the ID of the menu item.

13-18. The remaining lines of code are ignored for the moment. Because we chose Image Viewer, we came to this branch. If this code is executed for the first time, the window in m_PatternView is not created yet.

After the window in m_PatternView is created successfully, the window is displayed, and the task of this function is finished.


CPatternView

File Source Files/PatternView. cpp Header Files/PatternView. h

M_PatternView in the previous section is an object of the CPatternView class.


In CPatternView, the Create FUNCTION creation window initializes data. The OnCreate function is triggered because a window is created. OnCreate will enable a timer, and then trigger the response function OnTimer.

Okay, OnTimer is the focus of this class. OnTimer constantly reads the latest data and displays it in the window.


The bitmap information header is initialized as follows (in the Create FUNCTION)

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


From this, we can see that the bitmap displayed in the graphic viewer is 128 pixels in width and 256 pixels in height. It uses 8 bits to represent a color, that is, a 256 color image ), 16 colors are used, that is, the color palette has 16 colors ).


Before proceeding, insert some minor issues related to NES. There are two color palette images in the NES file, which are not considered for the moment), namely, the background color palette and the genie color palette. Each color palette occupies 16 bytes. Each byte is an index, representing one of the 256 colors.


Okay. Continue. There is a code in the end of the Create FUNCTION.

DirectDraw.GetPaletteData( m_Palette );


M_Palette is a byte array with a size of 256*4 bytes, which can represent exactly 256 colors. With the name of this variable added, I guess the function of this Code is to save the 256 colors indexed in m_Palette.


It's almost time to study the OnTimer function. The function code is messy together, so the function code can be pasted separately)

LPBYTE  pPAL = (m_SelectPal<4)?&BGPAL[m_SelectPal*4]:&SPPAL[(m_SelectPal&3)*4];    m_BitmapHdr.rgb[0] = m_Palette[pPAL[0]];    m_BitmapHdr.rgb[1] = m_Palette[pPAL[1]];    m_BitmapHdr.rgb[2] = m_Palette[pPAL[2]];    m_BitmapHdr.rgb[3] = m_Palette[pPAL[3]];

M_SelectPal is an integer ranging from 0 to 7. After you click the left mouse button, 1 is added. That is why the image above changes when you click the graphic viewer.

One or two lines of code are used to retrieve four color index values from the BGPAL background palette) or the SPPAL genie palette.

3-6 lines of code show that each image of the graphic viewer has only four colors.


M_lpPattern is a member variable of CPatternView. Stores the pixel data of the bitmap to be displayed. Run the following code to assign values to m_lpPattern:

for( INT i = 0; i < 8; i++ ) {        if( m_lpBank[i] != PPU_MEM_BANK[i] || PPU_MEM_TYPE[i] == BANKTYPE_CRAM ) {            m_lpBank[i] = PPU_MEM_BANK[i];            LPBYTE  lpPtn = PPU_MEM_BANK[i];            for( INT p = 0; p < 64; p++ ) {                LPBYTE  lpScn = &m_lpPattern[i*32*128+(p&15)*8+(p/16)*8*128];                for( INT y = 0; y < 8; y++ ) {                    BYTE    chr_l = lpPtn[y];                    BYTE    chr_h = lpPtn[y+8];                    lpScn[0] = ((chr_h>>6)&2)|((chr_l>>7)&1);                    lpScn[4] = ((chr_h>>2)&2)|((chr_l>>3)&1);                    lpScn[1] = ((chr_h>>5)&2)|((chr_l>>6)&1);                    lpScn[5] = ((chr_h>>1)&2)|((chr_l>>2)&1);                    lpScn[2] = ((chr_h>>4)&2)|((chr_l>>5)&1);                    lpScn[6] = ((chr_h>>0)&2)|((chr_l>>1)&1);                    lpScn[3] = ((chr_h>>3)&2)|((chr_l>>4)&1);                    lpScn[7] = ((chr_h<<1)&2)|((chr_l>>0)&1);                    // Next line                    lpScn+=128;                }                // Next pattern                lpPtn+=16;            }        }    }


PPU_MEM_BANK is a pointer array with a length of 12. The first eight pointers point to the pattern table, and the last four point to the name table or attribute table. Each Pointer Points to a space of 1 K.

To learn more about the graphic table, naming table, or attribute table, you can download the following document to see the graphic processor chapter.

Http://down.51cto.com/data/951473



The following describes my understanding of pattern tables, naming tables, and attribute tables.


The NES game screen is actually composed of 32*30 Tile, each of which has 8*8 pixels. The NES image has only 16 colors, so only four digits are needed to represent a pixel.

How do 8x8 pixels in each Tile be obtained?


The Tile number is saved in the naming table, and the Tile is stored in the pattern table. There are 256 Tile entries in a pattern table, so addressing a Tile requires one byte. The size of a naming table can be calculated. 1 byte * 32*30 = 960 bytes.


The pattern table stores two low pixels in the Tile. As mentioned above, one pattern table stores 256 Tile and one Tile has 8*8 pixels. The size of a pattern table is 2 bits * 256*8*8 = 32768 bits = 4096 bits = 4 kb

The pattern table stores a Tile in 16 bytes, of which 1 and 9 bytes are used to calculate the second row pixel of the Tile, 2 and 10 bytes are used to calculate the second row pixel, and so on. The specific calculation method is as follows: for example, the first pixel in 1st rows, the highest bit in 9th bytes, and the lowest Bit in 1st bytes. That is to say, the last eight bytes are 64-bit high, and the first eight bytes are 64-bit low. Assume that 1st bytes are 01010011 and 9th bytes are 10101111, then the first line of pixel is 2 1 2 1 2 3 3.


The attribute table is small. 1024 bytes of space. The name table occupies 960 bytes, and the remaining 64 bytes are reserved for the attribute table. The Attribute Table and the name table are paired. A byte in the Attribute Table stores 4*4 Tile-level two-digit pixels. Calculate the size of 32*32/4/4 = 64 bytes.


I have to say that this seemingly awkward processing method was quite good in the time when hardware resources were lacking.


Okay, continue back to our code.

This is the most important part of the code of the OnTimer function. To facilitate viewing, paste it again ).

for( INT i = 0; i < 8; i++ ) {        if( m_lpBank[i] != PPU_MEM_BANK[i] || PPU_MEM_TYPE[i] == BANKTYPE_CRAM ) {            m_lpBank[i] = PPU_MEM_BANK[i];            LPBYTE  lpPtn = PPU_MEM_BANK[i];            for( INT p = 0; p < 64; p++ ) {                LPBYTE  lpScn = &m_lpPattern[i*32*128+(p&15)*8+(p/16)*8*128];                for( INT y = 0; y < 8; y++ ) {                    BYTE    chr_l = lpPtn[y];                     BYTE    chr_h = lpPtn[y+8];                    lpScn[0] = ((chr_h>>6)&2)|((chr_l>>7)&1);                    lpScn[4] = ((chr_h>>2)&2)|((chr_l>>3)&1);                    lpScn[1] = ((chr_h>>5)&2)|((chr_l>>6)&1);                    lpScn[5] = ((chr_h>>1)&2)|((chr_l>>2)&1);                    lpScn[2] = ((chr_h>>4)&2)|((chr_l>>5)&1);                    lpScn[6] = ((chr_h>>0)&2)|((chr_l>>1)&1);                    lpScn[3] = ((chr_h>>3)&2)|((chr_l>>4)&1);                    lpScn[7] = ((chr_h<<1)&2)|((chr_l>>0)&1);                    // Next line                    lpScn+=128;                }                // Next pattern                lpPtn+=16;            }        }    }


With the above foundation, it is easy to read this code.

The Code contains three for loops. The number of cycles for each for loop took me a long time to understand. There are two pattern tables in NES, 1st for the background pattern table and 1st for the sprite pattern table. The author of the Code further divided a pattern table into four parts. Why? I don't know why, at least I haven't mentioned in my documents that I have divided one pattern table into four copies. In a word, 4*2, 8 will come out.

What does Row 3 mean? I still don't understand. When I debug the program, this judgment is basically true.

5th rows read Part 1 of the pattern table

The cycle of the 6th rows is more explicit here. One pattern table has 256 tile, and the 1/4 pattern table is 64 tile. We can see that the cycle is in tile. You can try to change 64 to 1, recompile the program, and run it. Then you can see what a tile is like.

The number of loops in the first row is 9th. The number of loops in the second row is 1 pixel. With the above explanation of the pattern table, we can understand how to find the specific one pixel.

One thing I want to talk about is that the sorting of 12-19 lines of code statements by the original author of the Code has really interfered with me for a long time. I have always thought that this sorting has specific meanings, if it is written as follows, the rule is obvious.

lpScn[0] = ((chr_h>>6)&2)|((chr_l>>7)&1);lpScn[1] = ((chr_h>>5)&2)|((chr_l>>6)&1);lpScn[2] = ((chr_h>>4)&2)|((chr_l>>5)&1);lpScn[3] = ((chr_h>>3)&2)|((chr_l>>4)&1);                  lpScn[4] = ((chr_h>>2)&2)|((chr_l>>3)&1);lpScn[5] = ((chr_h>>1)&2)|((chr_l>>2)&1);lpScn[6] = ((chr_h>>0)&2)|((chr_l>>1)&1);lpScn[7] = ((chr_h<<1)&2)|((chr_l>>0)&1);


The meaning of Row 3 is explained. Tile is square. After drawing a row of 8 pixels, you must add the lpScn Image Width 128 to the next row.

Rows 24th are relatively simple. The size of a tile in the pattern table is 16 bytes. to read the next tile, add 16 to the pattern table pointer lpPtn.



The code of the Image Viewer module is similar. The code of the scroll viewer is described in the next section. Scroll is the background. It's a hit. I learned the pattern table, naming table, and attribute table to see how the background is obtained based on these three tables.


This article from the "Three Take Tiger" blog, please be sure to keep this source http://darhx.blog.51cto.com/7920146/1300053

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.