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

📄 screen.cpp

📁 SNES game emulator. C and asm files.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*  SCREEN.CPP - SNES Screen Renderer
	Color depths (cdepth): 0=4 colors 1=16 colors 3=256 colors.
*/

#include "Common.hpp"
#include "GrEngine.hpp"
#include "CPU.hpp"
#include "emu65816.hpp"
#include "FileMan.hpp"
#include "GUI.hpp"
#include "SPC700.hpp"
#include "Screen.hpp"
#include <ASSERT.H>

//#define USE_C_SCREEN_CODE

int debugscreen;

int memdumpoffset = 0, vramdumpoffset = 0, oamdumpoffset = 0, cgramdumpoffset = 0;
int vramblitoffset = 0, vramblitcdepth = 0;

char vramcmpfn[40] = "";
byte debug_vram[65536];

union cachetile ctile [4][4096]; // 1MB!
byte cstatus [4096];
byte csolid [2][4096], cempty [2][4096];  // 8 bits, 1 for each scanline of the tile.
	// Two sets 0=no vertical flip, 1=vertical flip

struct cachetilemap ctmap [4][128][128], sprmap [128][8][8];
	// 1MB! + 64K
	// here's the deal with the ctmap (cached tile map): 4 BGs*128 max height*
	// 128 max width*2 priorities*8 bytes=1MB.  This stores a more useful version of the
	// tile maps.  The unused priority entry has it's "empty" byte set to 0xFF, so nothing
	// is drawn.  Every scanline, one line of this cached tile map is built from the tile
	// map data in VRAM (except that the same line will not be built two scanlines in a row,
	// so it may be up to 8 lines between line copies.)
	// Now, if the BG isn't large enough horizontally to fill 128 elements, it is copied so
	// that it does.  For example if it's 32 tiles wide, those 32 built tiles are copied
	// 4 times to fill 128 elements.

#define PRELINESIZE 272
byte bgline[4][2][272]; //4BGs*2Prios*263 Max pixels
byte mustcopybgline[4][2]; // Flags indicating whether bgline[] contains data
	// [x][8] = screen pixel 0
byte sprline[4][272]; // 4 Priorities
byte mustcopysprline[4];

byte spr8x8size [128]; // Set to 0 when cache entry is invalidated.

struct bginfo bg[4], *curbg;

union cachetile *translatetile (int taddress, byte cdepth, int flip)
{
	byte *tile = (byte*) &(ctile[flip][taddress]), *o_tile = tile;
	byte *addr = vram + (taddress << 4), *o_addr = addr, temp;
	signed char x, y, incaddr;
	boolean issolid = true, vflip = flip >> 1;
	byte *solidflags = &csolid[vflip][taddress], *emptyflags = &cempty[vflip][taddress];

	taddress &= 4095;
	if (flip & 2) {
		incaddr = -2;
		addr += 14;
	} else
		incaddr = 2;
	//debug0 ("  Caching tile; cstatus=%X cdepth=%d address=%d taddress=%d", cstatus[taddress], cdepth, taddress << 4, taddress);
	*solidflags = 0;
	*emptyflags = 0;
	switch (cdepth) {
	case 0:
		for (y = 0; y < 8; y++, tile += 8, addr += incaddr) {
			x = 7;
			do {
				tile[7-x] = ((addr[0] & (1<<x)) ?1:0) | (addr[1] & (1<<x) ?2:0);
				x--;
			} while (x >= 0);
			if ((addr[0] | addr[1]) == 0xFF) *solidflags |= (1 << y);
			else if ((addr[0] | addr[1]) == 0) *emptyflags |= (1 << y);
		}
		break;
	case 1:
		for (y = 0; y < 8; y++, tile += 8, addr += incaddr) {
			x = 7;
			do {
				tile[7-x] = (addr[0] & (1<<x) ?1:0) | (addr[1] & (1<<x) ?2:0) | (addr[16] & (1<<x) ?4:0) | (addr[17] & (1<<x) ?8:0);
				x--;
			} while (x >= 0);
			temp = addr[0] | addr[1] | addr[16] | addr[17];
			if (temp == 0xFF) *solidflags |= (1 << y);
			else if (temp == 0) *emptyflags |= (1 << y);
		}
		break;
	case 3:
		for (y = 0; y < 8; y++, tile += 8, addr += incaddr) {
			x = 7;
			do {
				tile[7-x] = (addr[0] & (1<<x) ?1:0) | (addr[1] & (1<<x) ?2:0) | (addr[16] & (1<<x) ?4:0) | (addr[17] & (1<<x) ?8:0) \
						  | (addr[32]& (1<<x)?16:0) | (addr[33]& (1<<x)?32:0) | (addr[48] & (1<<x)?64:0) | (addr[49] &(1<<x)?128:0);
				x--;
			} while (x >= 0);
			temp = addr[0] | addr[1] | addr[16] | addr[17] | addr[32] | addr[33] | addr[48] | addr[49];
			if (temp == 0xFF) *solidflags |= (1 << y);
			else if (temp == 0) *emptyflags |= (1 << y);
		}
		break;
	}
	cstatus [taddress] = cdepth | (cstatus [taddress] & 0xF0) | (16 << flip);
	tile = o_tile;
	if (flip & 1) {
		for (y = 0; y < 8; y++) {
			temp = tile[7]; tile[7] = tile[0]; tile[0] = temp;
			temp = tile[6]; tile[6] = tile[1]; tile[1] = temp;
			temp = tile[5]; tile[5] = tile[2]; tile[2] = temp;
			temp = tile[4]; tile[4] = tile[3]; tile[3] = temp;
			tile += 8;
		}
	}
	/*
	if ((taddress<<4) >= 0xC000 && (taddress<<4) < 0xC200) { // second row first ball
		for (y=0;y<8;y++) {
			debug0 ("    %d %02X %02X %02X %02X %02X %02X %02X %02X   P0:%04X", y,
			ctile[taddress].pixel[y*8], ctile[taddress].pixel[y*8+1],
			ctile[taddress].pixel[y*8+2], ctile[taddress].pixel[y*8+3],
			ctile[taddress].pixel[y*8+4], ctile[taddress].pixel[y*8+5],
			ctile[taddress].pixel[y*8+6], ctile[taddress].pixel[y*8+7],
			*((word*)&o_addr[y*2]));
		}
	}
	*/
	return &ctile [flip][taddress];
}

inline union cachetile *getcachetile (int taddress, byte cdepth, int flip)
{ // COLOR DEPTH: 0=2 bit 1=4 bit 3=8 bit
	if ((cstatus[taddress] & (16 << flip)) && (cstatus[taddress] & 0x3) == cdepth) {
		return &ctile [flip][taddress];
	} else {
		return translatetile (taddress, cdepth, flip);
	}
}

byte *screen, scanlines;
	// screen points to current scanline; scanlines = 224 or 239.

struct snesscreenmode {
	int bgs, onmask;
	byte cdepth[4];
} snesmode [8] = {
	{ 4, 0x1F, 0, 0, 0, 0 },
	{ 3, 0x17, 1, 1, 0 },
	{ 2, 0x13, 1, 1 },
	{ 2, 0x13, 3, 1 },
	{ 2, 0x13, 3, 0 },
	{ 2, 0x13, 1, 0 },
	{ 1, 0x11, 1 },
	{ 1, 0x11, 3 }
};

void resetscreenframe ()
{       // To be called at scanline 0...
	int x;

	//debug0 ("spriteline %P/%P/%P/%P", sprline[0], sprline[1], sprline[2], sprline[3]);
	screen = vs + 256*8;
	for (x = 0; x < 4; x++) {
		getbgframeinfo (x);
		bg[x].lastbgrow = -1;
	}
	for (x = 0; x < 256; x++) {
		setsnespalette (x, ((word*)cgram) [x], (*REG2100 & 0xF));
	}
	if ((*REG212C | *REG212D | curgs->bgs) & 0x10) {
		buildspritetable ();
		oamposchange = true;
	}
}

//--------------------------------------------------------------Info updating funcs

void getbgframeinfo (int plane)
{
	bg[plane].bgnum = plane + 1;
}

void getbglineinfo (int plane)
{
	bg[plane].cdepth = snesmode[*REG2105 & 7].cdepth[plane];
	bg[plane].tcharshift = (bg[plane].cdepth == 3 ? 2 : bg[plane].cdepth);
	if (*REG2105 & (16 << plane)) { // 16x16 tiles
		bg[plane].tile16x16 = true;
	} else {
		bg[plane].tile16x16 = false;
	}
	if (*REG2107(plane) & 2) { // SC Height
		bg[plane].height64 = true;
		//bg[plane].pixheight = (512 << bg[plane].tile16x16);
		//bg[plane].pixheightand = (bg[plane].tile16x16 ? 0x3FF : 0x1FF);
		bg[plane].height8x8 = (64 << bg[plane].tile16x16);
	} else {
		bg[plane].height64 = false;
		//bg[plane].pixheight = (256 << bg[plane].tile16x16);
		//bg[plane].pixheightand = (bg[plane].tile16x16 ? 0x1FF : 0xFF);
		bg[plane].height8x8 = (32 << bg[plane].tile16x16);
	}
	if (*(REG2107(plane)) & 1) { // SC Width
		bg[plane].width64 = true;
		//bg[plane].pixwidth = (512 << bg[plane].tile16x16);
		//bg[plane].pixwidthand = (bg[plane].tile16x16 ? 0x3FF : 0x1FF);
		//bg[plane].pixwidthshift = (9 + bg[plane].tile16x16);
		bg[plane].width8x8 = (64 << bg[plane].tile16x16);
	} else {
		bg[plane].width64 = false;
		//bg[plane].pixwidth = (256 << bg[plane].tile16x16);
		//bg[plane].pixwidthand = (bg[plane].tile16x16 ? 0x1FF : 0xFF);
		//bg[plane].pixwidthshift = (8 + bg[plane].tile16x16);
		bg[plane].width8x8 = (32 << bg[plane].tile16x16);
	}
	bg[plane].width8x8and = bg[plane].width8x8 - 1;
	bg[plane].height8x8and = bg[plane].height8x8 - 1;
	bg[plane].tilemap = vram + ((*REG2107(plane) & 0x7C) << 9); // Correct in demos
	bg[plane].tcharbase = ((*REG210B >> (plane << 2)) & 7) << 9; // Correct in demos
	bg[plane].scrollx = (state.scrollreg[plane << 1] & 0x7FF);
	bg[plane].scrolly = ((state.scrollreg[(plane<<1)+1] + 1) & 0x7FF);// & bg[plane].pixelheightmask);
	if ((*REG2105 & 7) == 0) // Mode 0
		bg[plane].cgoffs = (plane << 5);
	else
		bg[plane].cgoffs = 0;
}

//--------------------------------------------------BG scanline generators/blitters

int getwindowregion (byte fourflags, byte masklogic, int *start, int *end)
{	// Returns: -1 if NONE of the scanline is visible because of windowing
	//           0 if all the scanline is visible
	//           Otherwise, # of regions
	byte n = 0;
	byte l1 = *REG2126, r1 = *REG2127, l2 = *REG2128, r2 = *REG2129, temp;
	if (!(fourflags & 0xA))
		return 0;
	if (masklogic == 3) {
		masklogic = 2;
		fourflags ^= 5;
	}
	if ((fourflags & 0xA) == 8) // Enable Window 2 only, simulate window 1
		fourflags >>= 2;
	if ((fourflags & 0xA) == 2 || masklogic == 0) { // Window 1 enabled only or OR logic
//		debug0 ("%d: n%d %d-%d %d-%d", screen_scanline, n, l1, r1, l2, r2);
		if (fourflags & 1) { // Clip outside
			if (l1 > r1) {
				start[0] = 0;
				end[0] = 255;
				return 1;
			}
			if (l1 != 0) {
				start[n] = 0;
				end[n] = l1 - 1;
				n++;
			}
			if (r1 != 255) {
				start [n] = r1 + 1;
				end[n] = 255;
				n++;
			}
//			debug0 ("n%d start[0]%d end[0]%d start[1]%d end[1]%d", n, start[0], end[0], start[1], end[1]);
		} else { // Clip inside
			start [n] = l1;
			end [n] = r1;
			n++;
		}
		if (fourflags & 8) { // Two windows, OR logic
			if (fourflags & 4) { // Clip outside
				if (l2 > r2) {
					start[0] = 0;
					end[0] = 255;
					return 1;
				}
				if (l2 != 0) {
					start[n] = 0;
					end[n] = l2 - 1;
					n++;
				}
				if (r2 != 255) {
					start [n] = r2 + 1;
					end[n] = 255;
					n++;
				}
			} else { // Clip inside
				if (l2 == 0 && r2 == 255)
					n = 0;
				start [n] = l2;
				end [n] = r2;
				n++;
			}
		}
	} else { // Both windows, apply logic also
		if (l2 < l1) {
			temp = l1; l1 = l2; l2 = temp;
			temp = r1; r1 = r2; r2 = temp;
		}	// Now window 1 always starts before window 2
		if (masklogic == 1) { // AND logic
			
		} else { // XOR logic
		}
	}
	return n;
}

void generatebgscanline (int plane, boolean windowsenabled)
{
	int row, offsy, x, y, mosaic;
	boolean ismosaic;
	byte windowsetup, masklogic, nwin = 0;
	int start[4], end[4];

	if (curgs->bgs & (1 << plane)) {
		curbg = &bg[plane];
		ismosaic = (*REG2106 & (1 << plane)) && (*REG2106 & 0xF0) != 0;
		if (ismosaic) {
			mosaic = ((*REG2106 >> 4) + 1);
			curbg->scrolly = curbg->scrolly / mosaic * mosaic;
		}
		row = ((curbg->scrolly >> 3) & curbg->height8x8and);
		offsy = curbg->scrolly & 7;
		if (row != curbg->lastbgrow) {
			updatetilemaprow (row); // uses curbg
			curbg->lastbgrow = row;
		}
		if (windowsenabled) {
			windowsetup = (*(word*)REG2123 >> (plane << 2)) & 0xF;
			masklogic = (*REG212A >> (plane << 1)) & 0x3;
			if ((nwin = getwindowregion (windowsetup, masklogic, start, end)) == -1)
				return;
			if (screen_scanline == 16) {
//				debug0 ("plane %d sc%d nwin%d %d-%d", screen_scanline, nwin, start[0], end[0]);
			}
		}
		blitbgline (row, offsy, curbg->scrollx >> 3, bgline [plane][0] + 8 - (curbg->scrollx & 7), mustcopybgline[plane]);
		if ((*REG2105&7) == 7) {
			blitmode7line ();
		}
		if (!mustcopybgline[plane][0] && !mustcopybgline[plane][1])
			return;
		if (ismosaic) {
			for (x = 8; x < 264; x += mosaic) {
				for (y = mosaic - 1; y > 0; y--) {
					bgline [plane][0][x+y] = bgline [plane][0][x];
					bgline [plane][1][x+y] = bgline [plane][1][x];
				}
			}
		}
		if (windowsenabled) {
			for (y = 0; y < nwin; y++) {
				for (x = start[y]; x <= end[y]; x++) {
					bgline [plane][0][8+x] = bgline [plane][1][8+x] = 0;
				}
			}
		}
	}
}

#ifndef USE_C_SCREEN_CODE
extern void blitbgline_frontend (struct cachetilemap *ctilemap, int offsy, int col, byte *scrstart, byte *mustcopy);
#pragma aux blitbgline_frontend = \
	"push edx"\
	"mov ecx, [edx]"\
	"call blitbglineasm"\
	"pop edx"\
	"nop"\
	"mov [edx], cx"\
	parm [esi] [ebx] [eax] [edi] [edx]\
	modify [eax ebx ecx edx esi edi];
#endif

void blitbgline (int row, int offsy, int col, byte *scrstart, byte *mustcopy)
{
	struct cachetilemap *ctilemap = &ctmap[curbg->bgnum-1][row][col];

#ifdef USE_C_SCREEN_CODE
	int x, flagand = (1 << offsy); //pixoffsy = (offsy << 3);
	dword dwpal_or;

	offsy <<= 1;
	for (x = 33; x != 0; scrstart += 8, ctilemap++, col++, x--) {
		if (col & 0xFFFFFF80) { // 0 <= Column < 128
			col -= 128;
			ctilemap -= 128;
		}
		if (ctilemap->empty & flagand) {
			((dword*)(scrstart + PRELINESIZE))[0] = ((dword*)scrstart)[0] = 0;
			((dword*)(scrstart + PRELINESIZE))[1] = ((dword*)scrstart)[1] = 0;
		} else {
			if (ctilemap->prio) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -