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

📄 pgbcachedvideo.java

📁 一个用java写成的gb模拟器的源代码。
💻 JAVA
字号:
/**
 * this source file released under the GNU Public Licence.
 * see the accompanying copyright.txt for more information
 * Copyright (C) 2000-2001 Ben Mazur
 */

/**
 * PgbCachedIndexedVideo is a subclass of PgbIndexedVideo
 * that keeps copies of the tiles, background maps and
 * sprites cached.
 * 
 * It should be faster in most circumstances, as it does not
 * go back to the memory every time a tile is accessed.
 * Particularly, it does not have to blend the two display 
 * bytes together for each line in the tile.
 */
public class PgbCachedVideo extends PgbBasicVideo {
	
	// here's the memory
	byte[][][][]	tiles;
	byte[][][]		map;
	byte[][][]		sprites;
	int				lastTile;
	
	public PgbCachedVideo() {
		tiles = new byte[2][384][8][8]; // [bank][num][y][x]
		map = new byte[4][256][256];  // map, y, x
		sprites = new byte[40][16][8];
	}
	
	/**
	 * the heart of the operation.  monitors VRAM writes
	 * and updates the appropriate caches
	 */
	public void write(int address, byte towrite) {
		super.write(address, towrite);
		// tile storage
		if(address >= 0x8000 && address < 0x9800) {
			// this updates tiles in almost all circumstances
			checkTile(address);
		}
		// tile map at 9800
		if(address >= 0x9800 && address < 0x9C00) {
			updateMap(0, (address - 0x9800) & 0x1F, (address - 0x9800) >> 5, vram[address - 0x8000] + 256);
			updateMap(1, (address - 0x9800) & 0x1F, (address - 0x9800) >> 5, vram[address - 0x8000] & 0xFF);
			return;
		}
		// tile map at 9C00
		if(address >= 0x9C00 && address < 0xA000) {
			updateMap(2, (address - 0x9C00) & 0x1F, (address - 0x9C00) >> 5, vram[address - 0x8000] + 256);
			updateMap(3, (address - 0x9C00) & 0x1F, (address - 0x9C00) >> 5, vram[address - 0x8000] & 0xFF);
			return;
		}
		// OAM
		if(address >= 0xFE00 && address < 0xFEA0) {
			if((address & 0x02) == 0x02) {
				updateObj((address - 0xFE00) >> 2);
			}
			return;
		}
	}
	
	/**
	 * override to draw from the cache
	 */
	void doBgLine(int line) {
		int bgline, middle, i;
		byte[] srcmap;
		
		bgline = (line + scy) & 0xFF;
		srcmap = map[(chr_mode ? 1 : 0) + (bg_mode ? 2 : 0)][bgline];

		if(scx < 97) {
			System.arraycopy(srcmap, scx, screenMemory, line * 160, 160);
		} else {
			middle = 256 - scx;
			System.arraycopy(srcmap, scx, screenMemory, line * 160, middle);
			System.arraycopy(srcmap, 0, screenMemory, line * 160 + middle, 160 - middle);
		}
	}
	
	/**
	 * override to draw from the cache
	 */
	void doWinLine(int line) {
		if(wy > line || wx > 166) {
			return;
		}
		byte[] srcmap = map[(chr_mode ? 1 : 0) + (win_mode ? 2 : 0)][line - wy];
		int ws, ss, wl;
		if(wx < 7) {
			ws = 7 - wx;
			ss = 0;
			wl = 160 - ws;
		} else {
			ws = 0;
			ss = wx - 7;
			wl = 160 - ss;
		}
		System.arraycopy(srcmap, ws, screenMemory, line * 160 + ss, wl);
	}
	
	/**
	 * override to draw from cache
	 */
	void doObjLine(int line) {
		int s, so, sx, sy;
		for(s = 39; s >= 0; s--) {
			so = s * 4;
			sx = oam[so + 1] & 0xFF;
			sy = oam[so] & 0xFF;
			if((sx > 0 && sy > 0) && sy <= line + 16 && sy > line + (16 - obj_siz)) {
				// draw
				boolean shidden = (oam[so + 3] & 0x80) == 0x80;
				byte[] ssrc = sprites[s][line - sy + 16];
				for(int p = 0; p < 8; p++) {
					// grrr... transparency...
					int spx = sx - 8 + p;
					byte sp = ssrc[p];
					if((sp & 0x03) > 0  && spx < 160 && spx >= 0 
					   && (!(shidden || (getBackgroundAttr(spx, line) & 0x80) == 0x80) 
						   || ((screenMemory[line * 160 + spx] & 0x03) == 0))) {
						screenMemory[line * 160 + spx] = sp;
					}
				}
			}
		}
	}
	
	/**
	 * updates the screen maps at the specified coordinates
	 */
	void updateMap(int which, int x, int y, int tilenum) {
		// draw the tile on the map
		if(PgbSettings.system == PgbSettings.SYS_GBC) {
			// stupid GBC tile routine
			int i, mx, my, ty;
			int attribute = getAttr(x, y, (which & 2) == 2);//(which & 2) == 2 ? vram[0x3C00 + x + y * 32] : vram[0x3800 + x + y * 32];
			byte pal = (byte)((attribute & 0x07) << 3);
			int bank = (attribute & 0x08) == 0x08 ? 1 : 0;
			for(i = 0; i < 8; i++) {
				my = y * 8 + i;
				mx = x * 8;
				ty = ((attribute & 0x40) == 0x40) ? 7 - i : i;
				if((attribute & 0x20) == 0x20){
					// hflip
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][7]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][6]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][5]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][4]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][3]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][2]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][1]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][0]);
				} else {
					// !hflip
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][0]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][1]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][2]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][3]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][4]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][5]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][6]);
					map[which][my][mx++] = (byte)(pal | tiles[bank][tilenum][ty][7]);
				}
			}
		} else {
			// mono tile copy
			int mx = x * 8;
			int my = y * 8;
			System.arraycopy(tiles[0][tilenum][0], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][1], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][2], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][3], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][4], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][5], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][6], 0, map[which][my++],mx, 8);
			System.arraycopy(tiles[0][tilenum][7], 0, map[which][my++],mx, 8);
		}
	}
	
	/**
	 * updates the specified sprite cache
	 */
	public void updateObj(int onum) {
		int tnum = oam[(onum << 2) + 2] & (obj_mode ? 0xFE : 0xFF);
		byte attr = oam[(onum << 2) + 3];
		int bank;
		byte pal;
		if(PgbSettings.system == PgbSettings.SYS_GBC) {
			bank = attr >> 3 & 0x01;
			pal = (byte)((attr << 3 & 0x38) | 0x04);
		} else {
			bank = 0;
			pal = (byte)((attr >> 1 & 0x08) | 0x04);
		}
		boolean vflip = (attr & 0x40) == 0x40;
		boolean hflip = (attr & 0x20) == 0x20;
		int ts = (tnum * 16) + (0x2000 * bank);
		for(int y = 0; y < obj_siz; y++) {
			int ty = vflip ? obj_siz - y - 1 : y;
			copyTileLineArray(ts + ty * 2, hflip, pal, sprites[onum][y], 0);
		}
		/*
		tnum += vflip ? 1 : 0;
		for(int y = 0; y < 8; y++) {
			int ty = vflip ? 7 - y : y;
			for(int x = 0; x < 8; x++) {
				int tx = hflip ? 7 - x : x;
				sprites[onum][y][x] = (byte)(pal | tiles[bank][tnum][ty][tx]);
			}
		}
		if(obj_mode) {
			tnum += vflip ? -1 : 1;
			for(int y = 8; y < 16; y++) {
				int ty = vflip ? 15 - y : y - 8;
				for(int x = 0; x < 8; x++) {
					int tx = hflip ? 7 - x : x;
					sprites[onum][y][x] = (byte)(pal | tiles[bank][tnum][ty][tx]);
				}
			}
		}
		*/
	}
	
	/**
	 * check if we need to redraw this tile
	 * this isn't exactly perfect, but it'll do.
	 */
	void checkTile(int address) {
		int tilenum = (address - 0x8000) / 16;
		if((address & 0x0F) == 0x0F) {
			// if it's the last byte of a tile
			doTile(tilenum, gbcVram & 0x01);
		} else {
			// if they've left one off in the middle
			if(tilenum != lastTile) {
				doTile(lastTile, gbcVram & 0x01);
			}
		}
		lastTile = tilenum;
	}
	
	/**
	 * updates the tile cache
	 */
	void doTile(int tilenum, int bank) {
		int ts = tilenum * 16 + 0x2000 * bank;
		copyTileLineArray(ts + 0, tiles[bank][tilenum][0], 0);
		copyTileLineArray(ts + 2, tiles[bank][tilenum][1], 0);
		copyTileLineArray(ts + 4, tiles[bank][tilenum][2], 0);
		copyTileLineArray(ts + 6, tiles[bank][tilenum][3], 0);
		copyTileLineArray(ts + 8, tiles[bank][tilenum][4], 0);
		copyTileLineArray(ts + 10, tiles[bank][tilenum][5], 0);
		copyTileLineArray(ts + 12, tiles[bank][tilenum][6], 0);
		copyTileLineArray(ts + 14, tiles[bank][tilenum][7], 0);

		scanUpdateTile(tilenum);
	}
	
	/**
	 * Scans the screen maps and updates a tile when tile
	 * data is changed.  
	 * 
	 * This is sort of the weakness of the tile/map caching 
	 * scheme -- whenever a tile is changed, you must then
	 * update all instances of the tile in the map.  This
	 * makes it pretty easy, tho.
	 */
	void scanUpdateTile(int tilenum) {
		byte tn = (byte)(tilenum);
		for(int i = 0x1800; i < 0x1C00; i++) {
			if(vram[i] == tn) {
				if(tilenum > 127) {
					updateMap(0, (i - 0x1800) & 0x1F, (i - 0x1800) >> 5, tilenum);
				}
				if(tilenum < 256) {
					updateMap(1, (i - 0x1800) & 0x1F, (i - 0x1800) >> 5, tilenum);
				}
			}
		}
		for(int i = 0x1C00; i < 0x2000; i++) {
			if(vram[i] == tn) {
				if(tilenum > 127) {
					updateMap(2, (i - 0x1C00) & 0x1F, (i - 0x1C00) >> 5, tilenum);
				}
				if(tilenum < 256) {
					updateMap(3, (i - 0x1C00) & 0x1F, (i - 0x1C00) >> 5, tilenum);
				}
			}
		}
	}
}

⌨️ 快捷键说明

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