📄 gfx.cpp
字号:
// Now add the tile offset to the base address of the
// name table to get the address of the tile
add pbyNameTableTile, eax
// Get the upper color of the tile. This is done by
// getting the attribute byte and then ANDing the byte
// by the correct bits for the tile (see yoshi's nes doc).
// Rather that doing a series of calculations to find the
// attribute offset and what bits to and the byte with,
// all that info is stored in lookup table arrays.
xor ebx, ebx
mov ecx, pbyAttributeTable
mov bl, [AttributeBytes+eax] // bl=offset into the attribute table
mov dl, [ecx+ebx] // dl=attribute byte
mov dh, [AttributeBits+eax] // dh=attribute bits to AND the attribute byte by
mov cl, [UpColRotateVal+eax] // cl=number of bits to rotate the upper color by
and dl, dh // dl=upper color for the tile but in the right bit position
ror dl, cl // dl=upper color of the tile
mov byUpperColor, dl
// TILEADDRESS = (TILENUM * 16) + PATTERNTABLE
xor eax, eax
mov ecx, pbyNameTableTile
mov al, BYTE PTR [ecx]
shl ax, 4
add eax, pbyCurPatternTableAddr // eax = TILEADDRESS
// SCANLINE_ADDRESS = TILEADDRESS + (Scanline % 8)
add eax, byScanlineMOD8 // eax=SCANLINE_ADDRESS
// Adjust the tile for horizontal scrolling
xor ecx, ecx
mov cx, relx
and cx, 7
mov edi, 8
sub edi, ecx
mov bl, [eax]
mov dl, [eax+8]
rcl bl, cl
rcl dl, cl
jmp dsh_SkipForFirstTile
//-----------------------------
// Draw the piece of the tile
//-----------------------------
dsh_DrawTileBeginning:
// Move the pattern table bytes into registers.
mov bl, [eax]
mov dl, [eax+8]
dsh_SkipForFirstTile:
// Move the x coordinate into a register to speed up things.
mov si, x
dsh_DrawTileLoop:
// Calculate the color of the pixel, where eax
// points to the memory location of the pattern table
// tile being used.
rcl bl, 1
setc cl
rcl dl, 1
setc al
shl al, 1
or cl, al
// Draw the pixel if the color is not 0
jz dsh_DontDrawPixel
// Add the upper part of the color to the color.
// NOW bl=The index into the NES's palette.
or cl, byUpperColor
// Save all our registers so they don't get modified
// in the put pixel routine.
push eax
push ebx
push edx
push esi
// Put the pixel on the screen surface.
push ecx
call PutBackgroundPixel
// Restore all our saved registers.
pop esi
pop edx
pop ebx
pop eax
dsh_DontDrawPixel:
// Advance the pointer to video memory to the next pixel.
mov ecx, lBytesPerPixel
add pSurfaceMemory, ecx
// Move our position indicators to the next pixel.
inc si
inc relx
// Check to see if were done with the scanline
cmp si, SCREEN_WIDTH
jge dsh_Done
// Decrement our counter by 1, when its zero that means we've
// drawn all the pixels for that tile on the current scanline.
dec edi
jnz dsh_DrawTileLoop
// Restore the x variable.
mov x, si
// We may need to change name tables during the process
cmp relx, SCREEN_WIDTH
jge dsh_NewNameTable
// Get the new tile by incrementing the pointer that
// points to the current tile and then getting the
// new tile address into the pattern table, then get
// the scanline address
inc pbyNameTableTile
inc wTileNum
dsh_GetTileAddress:
// Get the upper color of the tile. This is done by
// getting the attribute byte and then ANDing the byte
// by the correct bits for the tile (see yoshi's nes doc).
// Rather that doing a series of calculations to find the
// attribute offset and what bits to and the byte with,
// all that info is stored in lookup table arrays.
xor ebx, ebx
xor edi, edi
mov di, wTileNum
mov ecx, pbyAttributeTable
mov bl, [AttributeBytes+edi] // bl=offset into the attribute table
mov dl, [ecx+ebx] // dl=attribute byte
mov dh, [AttributeBits+edi] // dh=attribute bits to AND the attribute byte by
mov cl, [UpColRotateVal+edi] // cl=number of bits to rotate the upper color by
and dl, dh // dl=upper color for the tile but in the right bit position
ror dl, cl // dl=upper color of the tile
mov byUpperColor, dl
// Get the index into the pattern table and store it in al
xor eax, eax
mov ebx, pbyNameTableTile
mov al, BYTE PTR [ebx]
// TILEADDRESS = (TILENUM * 16) + PATTERNTABLE
shl eax, 4
add eax, pbyCurPatternTableAddr ; eax = TILEADDRESS
// SCANLINE_ADDRESS = TILEADDRESS + (Scanline % 8)
add eax, byScanlineMOD8 ; ax=SCANLINE_ADDRESS
mov edi, 8
jmp dsh_DrawTileBeginning
dsh_NewNameTable:
// Get the beggining tile number that we computed at the
// beggining of this function since it is the same
// it just uses a different tile number.
// NOTE: HScroll does not play a factor in this since
// we will always start at the left of the new name table
xor eax, eax
mov ax, wBegTileNum
mov wTileNum, ax
// Now add the offset to the new name table address
// to get the new tile address
mov ebx, pabyNameTables
add ebx, 4
mov ebx, [ebx]
mov pbyNameTableTile, ebx
mov pbyAttributeTable, ebx
add pbyAttributeTable, 03C0h
add pbyNameTableTile, eax
mov relx, 0
xor eax, eax
mov ebx, pbyNameTableTile
mov al, byte ptr [ebx] // al=TILENUM
// TILEADDRESS = (TILENUM * 16) + PATTERNTABLE
shl eax, 4
add eax, pbyCurPatternTableAddr // eax = TILEADDRESS
// SCANLINE_ADDRESS = TILEADDRESS + (Scanline % 8)
add eax, byScanlineMOD8 // ax=SCANLINE_ADDRESS
// Get the upper color of the tile. This is done by
// getting the attribute byte and then ANDing the byte
// by the correct bits for the tile (see yoshi's nes doc).
// Rather that doing a series of calculations to find the
// attribute offset and what bits to and the byte with,
// all that info is stored in lookup table arrays.
xor ebx, ebx
xor edi, edi
mov di, wTileNum
mov ecx, pbyAttributeTable
mov bl, [AttributeBytes+edi] // bl=offset into the name table
add ecx, ebx // now points to attribute byte for the tile
mov dl, [ecx] // dl=attribute byte
mov dh, [AttributeBits+edi] // dh=attribute bits to AND the attribute byte by
and dl, dh // dl=upper color for the tile but in the right bit position
mov cl, [UpColRotateVal+edi] // cl=number of bits to rotate the upper color by
ror dl, cl // dl=upper color of the tile
mov byUpperColor, dl
mov edi, 8
jmp dsh_DrawTileBeginning
dsh_Done:
popad
}
return;
} // end DrawScanlineH()
//------------------------------------------------------------------------------
// Name: DoSprite0()
// Desc: Sets the sprite #0 flag when the scanline equals the y coordinate
// of sprite #0
//------------------------------------------------------------------------------
VOID DoSprite0()
{
// If the scanline = the y coordinate of sprite #0, then
// set bit #6 of register $2002
if (wScanline == (abySPRRAM[0] + 8))
CPU.Memory[0x2002] |= 0x40;
} // end DoSprite0()
//------------------------------------------------------------------------------
// Name: DrawScanlineSprites()
// Desc: Draws all the sprites that on the current scanline.
//------------------------------------------------------------------------------
VOID DrawScanlineSprites()
{
// Draw Sprite #0 separatly from the rest of the sprites
// becuase we have to check for the Sprite #0 hit flag.
DoSprite0();
// Loop through the rest of the sprites and draw each
// scanline of the sprite.
for (int i = 0; i < 63; i++)
DrawSpriteLine(i);
} // end DrawScanlineSprites()
//------------------------------------------------------------------------------
// Name: DrawSprites()
// Desc: Draws all the sprites either in front or behind the background.
//------------------------------------------------------------------------------
VOID DrawSprites(BYTE byPriority)
{
// Loop through all the sprites and display them if their
// priority bit is equal to the bit passed in.
if (CPU.Memory[0x2001] & 0x10)
for (int i = 63; i >= 0; i--)
if ((abySPRRAM[((i*4)+2)]&0x20) == byPriority)
DrawSprite(i);
} // end DrawSprites()
//------------------------------------------------------------------------------
// Name: DrawSprite()
// Desc: Draws a 8x8 or 8x16 pixel sprite.
//------------------------------------------------------------------------------
VOID DrawSprite(BYTE bySpriteNum)
{
BYTE byColor; // Index into the NES palette for the sprite.
BYTE* pbyTileByte; // Pointer to the pattern table byte.
BYTE* pSaveVideoMemStart = pSurfaceMemory;
// Save all the information about the sprite.
BYTE byYPos = abySPRRAM[(bySpriteNum*4)] + 1;
BYTE byTileNum = abySPRRAM[(bySpriteNum*4)+1];
BYTE byAttributes = abySPRRAM[(bySpriteNum*4)+2];
BYTE byXPos = abySPRRAM[(bySpriteNum*4)+3];
BYTE byUpperColor = (byAttributes & 0x3) << 2;
// Get the pointer to the tile byte in the pattern table for the sprite.
pbyTileByte = (byTileNum * 16) + PPU.apbyPatternTables[(CPU.Memory[0x2000]&0x08)>>3];
// Move the video memory pointer to where the sprite is supposed to be horizontally.
if (byAttributes & 0x40)
pSurfaceMemory += (byXPos * lBytesPerPixel) + (7 * lBytesPerPixel);
else
pSurfaceMemory += byXPos * lBytesPerPixel;
// Move the video memory pointer to where the sprite is supposed to be vertically.
if (byAttributes & 0x80)
pSurfaceMemory += ((byYPos + 7) * lSurfacePitch);
else
pSurfaceMemory += byYPos * lSurfacePitch;
// Draw the sprite by drawing each tile line then moving to the next byte.
for (int i = 0; i < 8; i++)
{
BYTE byTestBit = 0x80; // Color testing bit for the sprite tile.
BYTE byColorShiftVal = 7; // Number of bits to shift the color by.
while (byTestBit != 0)
{
// The color is the to lower bits from the pattern table
// obtained in the same way as a background tile plus the
// two uppercolor bits in the lower 2 bits of the attribute
// byte.
byColor = ((*pbyTileByte & byTestBit) >> byColorShiftVal) |
(((*(pbyTileByte+8) & byTestBit) >> byColorShiftVal) << 1);
// Draw the pixel on the screen if the color is not 0.
if (byColor != 0)
PutSpritePixel(byColor | byUpperColor);
// Move to the next pixel.
if (byAttributes & 0x40)
pSurfaceMemory -= lBytesPerPixel;
else
pSurfaceMemory += lBytesPerPixel;
byColorShiftVal--;
byTestBit >>= 1;
}
// Reset the horizontal video position for the next line.
if (byAttributes & 0x40)
pSurfaceMemory += (8 * lBytesPerPixel);
else
pSurfaceMemory -= (8 * lBytesPerPixel);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -