⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gfx.cpp

📁 nes游戏模拟器
💻 CPP
📖 第 1 页 / 共 3 页
字号:

		// 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 + -