📄 pgbvideo.java
字号:
/**
* this source file released under the GNU Public Licence.
* see the accompanying copyright.txt for more information.
* Copyright (C) 2000-2001 Ben Mazur
* modified by retroK 2004 http://aep-emu.de/
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* PgbVideo is responsible for the GameBoy video hardware.
*
* Additionally, some SGB memory and functions are contained
* here.
*
* It is abstract because it only makes sure that the VRAM,
* etc., contain the proper values. PgbVideoOutput classes
* depend on the getScreenPixels, etc methods
*/
public abstract class PgbVideo {
static final int VBLANK_CYCLES = 109;
static final int HBLANK_CYCLES = 49;
static final int OAM_CYCLES = 20;
static final int TRANSFER_CYCLES = 40;
static final byte STAT_HBLANK = 0;
static final byte STAT_VBLANK = 1;
static final byte STAT_OAM = 2;
static final byte STAT_TRANSFER = 3;
static final byte INT_LYC = 0x40;
static final byte INT_OAM = 0x20;
static final byte INT_HBLANK = 0x10;
static final byte INT_VBLANK = 0x08;
static final byte INT_LYCMODE = 0x04;
// output
PgbVideoOutput vidout;
// registers
public int scx;
public int scy;
public int ly;
public int lyc;
public int wx;
public int wy;
// lcdc
public boolean lcd_on;
public boolean win_on;
public boolean win_mode;
public boolean chr_mode;
public boolean bg_mode;
public boolean obj_mode;
public boolean obj_on;
public boolean bg_on;
public int win_src;
public int bg_src;
public int obj_siz;
public int chr_src;
// stat
public boolean int_lyc;
public boolean int_oam;
public boolean int_hblank;
public boolean int_vblank;
public byte stat_mode;
// counters
int cycles;
int curframe;
public long framecount;
// memory
byte[] vram;
byte[] oam;
// regular gb palettes
public int bgpal;
public int objpal0;
public int objpal1;
// SGB memory
boolean sgbvramon;
byte sgbPicture[];
byte sgbCharset[];
byte sgbPalette[];
byte sgbSystemPalette[];
byte sgbAtfData[];
byte sgbPaletteOverlay[];
// color gb
byte[] gbcPalette;
byte gbcVram;
int vramOffset;
byte bgpi;
byte obpi;
public PgbVideo() {
// setup ram
vram = new byte[0x4000];
oam = new byte[0xA0];
// sgb
sgbPicture = new byte[0x1000];
sgbCharset = new byte[0x4000];
sgbPalette = new byte[0x20];
sgbSystemPalette = new byte[0x1000];
sgbAtfData = new byte[0x1800];
sgbPaletteOverlay = new byte[90];
// gbc
gbcPalette = new byte[0x80];
}
public void reset() {
int i;
// blank ram
for(i = 0; i < 0x4000; i++) {
vram[i] = 0;
}
for(i = 0; i < 0xA0; i++) {
oam[i] = 0;
}
// registers
setLcdc((byte)0x91);
setStat((byte)0x80);
scy = 0;
scx = 0;
wx = 0;
wy = 0;
ly = 0;
lyc = 0;
cycles = 0;
curframe = 0;
framecount = 0;
// bgpal
setBgPal(0xFC);
setObjPal0(0xFF);
setObjPal1(0xFF);
// super GB
sgbvramon = false;
// gbc
vramOffset = 0x8000;
gbcVram = (byte)0x00;
bgpi = (byte)0x00;
obpi = (byte)0x00;
}
public byte read(int address) {
// VRAM
if(address >= 0x8000 && address < 0xA000) {
return vram[address - vramOffset];
}
// OAM
if(address >= 0xFE00 && address < 0xFEA0) {
return oam[address - 0xFE00];
}
System.out.println("Read from unmapped video memory:" + Integer.toHexString(address));
return 0;
}
public void write(int address, byte towrite) {
/*
// SGB
if(sgbvramon) {
System.out.print(Integer.toHexString(address & 0xFFFF) + ":" + Integer.toHexString(towrite & 0xFF) + " ");
}
*/
// VRAM
if(address >= 0x8000 && address < 0xA000) {
vram[address - vramOffset] = towrite;
return;
}
// OAM
if(address >= 0xFE00 && address < 0xFEA0) {
oam[address - 0xFE00] = towrite;
return;
}
System.out.println("Write to unmapped video memory:" + Integer.toHexString(address) + ", " + Integer.toHexString(towrite));
}
/**
* how many cycles until the next possible interrupt?
*/
public int cyclesLeft() {
return cycles;
}
/**
* this is called to update the LCD cycles
*/
public int cycle(int cy, PgbMemory pgbmemory) {
byte interrupt = 0;
cycles -= cy;
if(cycles <= 0) {
if(stat_mode == STAT_HBLANK || stat_mode == STAT_VBLANK) {
if(++ly > 0x100) {
ly = 0;
}
if(ly < 0x90) {
hblank();
stat_mode = STAT_OAM;
cycles = (int)(OAM_CYCLES * PgbSettings.clockspeed);
interrupt |= int_hblank ? PgbMemory.INT_LCD : 0;
} else {
stat_mode = STAT_VBLANK;
cycles = (int)(VBLANK_CYCLES * PgbSettings.clockspeed);
if(ly == 0x90) {
vblank();
// by retroK:
pgbmemory.soundPlay();
interrupt |= int_vblank ? (PgbMemory.INT_LCD | PgbMemory.INT_VBLANK) : PgbMemory.INT_VBLANK;
}
}
// coincidence interrupt
if(ly == lyc) {
interrupt |= int_lyc ? PgbMemory.INT_LCD : 0;
}
return interrupt;
}
if(stat_mode == STAT_OAM) {
stat_mode = STAT_TRANSFER;
cycles = (int)(TRANSFER_CYCLES * PgbSettings.clockspeed);
interrupt |= int_oam ? PgbMemory.INT_LCD : 0;
return interrupt;
}
if(stat_mode == STAT_TRANSFER) {
stat_mode = STAT_HBLANK;
cycles = (int)(HBLANK_CYCLES * PgbSettings.clockspeed);
return interrupt;
}
}
return 0;
}
public void hblank() {
//if(lcd_on && curframe == 0 && (ly & 1) == (framecount & 1)) {
if(lcd_on && curframe == 0) {
vidout.hblank(ly);
}
}
public void vblank() {
framecount++;
curframe--;
if(curframe < 0) {
curframe = PgbSettings.frameskip;
vidout.vblank();
}
}
public void setVideoOutput(PgbVideoOutput vidout) {
this.vidout = vidout;
}
public abstract byte[] getScreenMemory();
public abstract byte getScreenMemory(int index);
public abstract byte getScreenRed(byte index);
public abstract byte getScreenGreen(byte index);
public abstract byte getScreenBlue(byte index);
public abstract int getScreenColor(byte index);
public void setBgPal(int pval) {
//System.out.println("Change background palette: " + Integer.toHexString(pval));
bgpal = pval;
}
public void setObjPal0(int pval) {
//System.out.println("Change obj 0 palette: " + Integer.toHexString(pval));
objpal0 = pval;
}
public void setObjPal1(int pval) {
//System.out.println("Change obj 1 palette: " + Integer.toHexString(pval));
objpal1 = pval;
}
public void setLcdc(byte lval) {
boolean old_lcd = lcd_on;
lcd_on = (lval & 0x80) == 0x80;
win_mode = (lval & 0x40) == 0x40;
win_on = (lval & 0x20) == 0x20;
chr_mode = (lval & 0x10) == 0x10;
bg_mode = (lval & 0x08) == 0x08;
obj_mode = (lval & 0x04) == 0x04;
obj_on = (lval & 0x02) == 0x02;
bg_on = (lval & 0x01) == 0x01;
win_src = win_mode ? 0x9C00 : 0x9800;
chr_src = chr_mode ? 0x8000 : 0x8800;
bg_src = bg_mode ? 0x9C00 : 0x9800;
obj_siz = obj_mode ? 16 : 8;
// reset ly when LCD goes off to on?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -