mirror of https://github.com/bsnes-emu/bsnes.git
Update to v082r11 release.
byuu says: Emulates grayscale and color emphasis modes, improves sprite timing and PPU bus fetching behavior with the PPU disabled.
This commit is contained in:
parent
278cf8462c
commit
cb3460a673
|
@ -75,6 +75,6 @@ clean:
|
|||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-gameboy ui-libsnes ui-snes Makefile cc.bat clean.bat sync.sh
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes ui-snes Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
struct Interface {
|
||||
virtual void video_refresh(const uint32_t *data) {}
|
||||
virtual void video_refresh(const uint16_t *data) {}
|
||||
virtual void audio_sample(int16_t sample) {}
|
||||
virtual int16_t input_poll(bool port, unsigned device, unsigned id) { return 0; }
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
namespace NES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bnes";
|
||||
static const char Version[] = "000.06";
|
||||
static const char Version[] = "000.07";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,25 +38,6 @@ void PPU::frame_edge() {
|
|||
}
|
||||
|
||||
void PPU::power() {
|
||||
paletteRGB = {
|
||||
0x7c7c7c, 0x0000fc, 0x0000bc, 0x4428bc,
|
||||
0x940084, 0xa80020, 0xa81000, 0x881400,
|
||||
0x503000, 0x007800, 0x006800, 0x005800,
|
||||
0x004058, 0x000000, 0x000000, 0x000000,
|
||||
0xbcbcbc, 0x0078f8, 0x0058f8, 0x6844fc,
|
||||
0xd800cc, 0xe40058, 0xf83800, 0xe45c10,
|
||||
0xac7c00, 0x00b800, 0x00a800, 0x00a844,
|
||||
0x008888, 0x000000, 0x000000, 0x000000,
|
||||
0xf8f8f8, 0x3cbcfc, 0x6888fc, 0x9878f8,
|
||||
0xf878f8, 0xf85898, 0xf87858, 0xfca044,
|
||||
0xf8b800, 0xb8f818, 0x58d854, 0x58f898,
|
||||
0x00e8d8, 0x787878, 0x000000, 0x000000,
|
||||
0xfcfcfc, 0xa4e4fc, 0xb8b8b8, 0xd8d8f8,
|
||||
0xf8b8f8, 0xf8a4c0, 0xf0d0b0, 0xfce0a8,
|
||||
0xf8d878, 0xd8f878, 0xb8f8b8, 0xb8f8d8,
|
||||
0x00fcfc, 0xf8d8f8, 0x000000, 0x000000,
|
||||
};
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -82,9 +63,7 @@ void PPU::reset() {
|
|||
status.vram_increment = 1;
|
||||
|
||||
//$2001
|
||||
status.intensify_blue = false;
|
||||
status.intensify_green = false;
|
||||
status.intensify_red = false;
|
||||
status.emphasis = 0;
|
||||
status.sprite_enable = false;
|
||||
status.bg_enable = false;
|
||||
status.sprite_edge_enable = false;
|
||||
|
@ -132,7 +111,8 @@ uint8 PPU::read(uint16 addr) {
|
|||
result = status.bus_data;
|
||||
status.bus_data = cartridge.ciram_read(addr);
|
||||
} else if(addr <= 0x3fff) {
|
||||
result = status.bus_data = cgram_read(addr);
|
||||
result = cgram_read(addr);
|
||||
status.bus_data = cartridge.ciram_read(addr);
|
||||
}
|
||||
status.vaddr += status.vram_increment;
|
||||
break;
|
||||
|
@ -156,9 +136,7 @@ void PPU::write(uint16 addr, uint8 data) {
|
|||
status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10);
|
||||
return;
|
||||
case 1: //PPUMASK
|
||||
status.intensify_blue = data & 0x80;
|
||||
status.intensify_green = data & 0x40;
|
||||
status.intensify_red = data & 0x20;
|
||||
status.emphasis = data >> 5;
|
||||
status.sprite_enable = data & 0x10;
|
||||
status.bg_enable = data & 0x08;
|
||||
status.sprite_edge_enable = data & 0x04;
|
||||
|
@ -215,7 +193,9 @@ void PPU::ciram_write(uint16 addr, uint8 data) {
|
|||
|
||||
uint8 PPU::cgram_read(uint16 addr) {
|
||||
if((addr & 0x13) == 0x10) addr &= ~0x10;
|
||||
return cgram[addr & 0x1f];
|
||||
uint8 data = cgram[addr & 0x1f];
|
||||
if(status.grayscale) data &= 0x30;
|
||||
return data;
|
||||
}
|
||||
|
||||
void PPU::cgram_write(uint16 addr, uint8 data) {
|
||||
|
@ -233,7 +213,7 @@ void PPU::cgram_write(uint16 addr, uint8 data) {
|
|||
//XXXXX = X nametable (x:d3-d7)
|
||||
|
||||
bool PPU::raster_enable() const {
|
||||
return status.bg_enable || status.sprite_enable;
|
||||
return (status.bg_enable || status.sprite_enable);
|
||||
}
|
||||
|
||||
unsigned PPU::nametable_addr() const {
|
||||
|
@ -248,6 +228,22 @@ unsigned PPU::scrolly() const {
|
|||
return (((status.vaddr >> 5) & 0x1f) << 3) | ((status.vaddr >> 12) & 7);
|
||||
}
|
||||
|
||||
unsigned PPU::sprite_height() const {
|
||||
return status.sprite_size == 0 ? 8 : 16;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8 PPU::chr_load(uint16 addr) {
|
||||
if(raster_enable() == false) return 0x00;
|
||||
return cartridge.chr_read(addr);
|
||||
}
|
||||
|
||||
uint8 PPU::ciram_load(uint16 addr) {
|
||||
if(raster_enable() == false) return 0x00;
|
||||
return cartridge.ciram_read(addr);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void PPU::ly_increment() {
|
||||
|
@ -259,6 +255,7 @@ void PPU::ly_increment() {
|
|||
}
|
||||
|
||||
void PPU::scrollx_increment() {
|
||||
if(raster_enable() == false) return;
|
||||
status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f);
|
||||
if((status.vaddr & 0x001f) == 0x0000) {
|
||||
status.vaddr ^= 0x0400;
|
||||
|
@ -266,6 +263,7 @@ void PPU::scrollx_increment() {
|
|||
}
|
||||
|
||||
void PPU::scrolly_increment() {
|
||||
if(raster_enable() == false) return;
|
||||
status.vaddr = (status.vaddr & 0x0fff) | ((status.vaddr + 0x1000) & 0x7000);
|
||||
if((status.vaddr & 0x7000) == 0x0000) {
|
||||
status.vaddr = (status.vaddr & 0x7c1f) | ((status.vaddr + 0x0020) & 0x03e0);
|
||||
|
@ -279,10 +277,11 @@ void PPU::scrolly_increment() {
|
|||
//
|
||||
|
||||
void PPU::raster_pixel(unsigned x) {
|
||||
uint32 *output = buffer + status.ly * 256;
|
||||
uint16 *output = buffer + status.ly * 256;
|
||||
|
||||
unsigned mask = 0x8000 >> (status.xaddr + x);
|
||||
unsigned palette = 0;
|
||||
unsigned palette = 0, object_palette = 0;
|
||||
bool object_priority = 0;
|
||||
palette |= (raster.tiledatalo & mask) ? 1 : 0;
|
||||
palette |= (raster.tiledatahi & mask) ? 2 : 0;
|
||||
if(palette) {
|
||||
|
@ -293,7 +292,7 @@ void PPU::raster_pixel(unsigned x) {
|
|||
|
||||
if(status.bg_edge_enable == false && status.lx < 8) palette = 0;
|
||||
|
||||
for(unsigned sprite = 0; sprite < 8; sprite++) {
|
||||
for(signed sprite = 7; sprite >= 0; sprite--) {
|
||||
if(status.sprite_edge_enable == false && status.lx < 8) continue;
|
||||
if(raster.oam[sprite].id == 64) continue;
|
||||
|
||||
|
@ -310,14 +309,37 @@ void PPU::raster_pixel(unsigned x) {
|
|||
if(raster.oam[sprite].id == 0 && palette) status.sprite_zero_hit = 1;
|
||||
sprite_palette |= (raster.oam[sprite].attr & 3) << 2;
|
||||
|
||||
if((raster.oam[sprite].attr & 0x20) == 0 || palette == 0) {
|
||||
palette = 16 + sprite_palette;
|
||||
break;
|
||||
}
|
||||
object_priority = raster.oam[sprite].attr & 0x20;
|
||||
object_palette = 16 + sprite_palette;
|
||||
}
|
||||
|
||||
if(object_palette) {
|
||||
if(palette == 0 || object_priority == 0) palette = object_palette;
|
||||
}
|
||||
|
||||
if(raster_enable() == false) palette = 0;
|
||||
output[status.lx++] = paletteRGB[cgram[palette]];
|
||||
output[status.lx++] = (status.emphasis << 6) | cgram_read(palette);
|
||||
}
|
||||
|
||||
void PPU::raster_sprite() {
|
||||
if(status.sprite_enable == false) return;
|
||||
|
||||
unsigned n = raster.oam_iterator++;
|
||||
signed ly = (status.ly == 261 ? -1 : status.ly);
|
||||
unsigned y = ly - oam[(n * 4) + 0];
|
||||
|
||||
if(y >= sprite_height()) return;
|
||||
if(raster.oam_counter == 8) {
|
||||
status.sprite_overflow = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
raster.soam[raster.oam_counter].id = n;
|
||||
raster.soam[raster.oam_counter].y = y;
|
||||
raster.soam[raster.oam_counter].tile = oam[(n * 4) + 1];
|
||||
raster.soam[raster.oam_counter].attr = oam[(n * 4) + 2];
|
||||
raster.soam[raster.oam_counter].x = oam[(n * 4) + 3];
|
||||
raster.oam_counter++;
|
||||
}
|
||||
|
||||
void PPU::raster_scanline() {
|
||||
|
@ -327,12 +349,20 @@ void PPU::raster_scanline() {
|
|||
return ly_increment();
|
||||
}
|
||||
|
||||
uint32 *output = buffer + status.ly * 256;
|
||||
signed lx = 0, ly = (status.ly == 261 ? -1 : status.ly);
|
||||
status.lx = 0;
|
||||
|
||||
raster.oam_iterator = 0;
|
||||
raster.oam_counter = 0;
|
||||
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
raster.soam[n].id = 64;
|
||||
raster.soam[n].tiledatalo = 0;
|
||||
raster.soam[n].tiledatahi = 0;
|
||||
}
|
||||
|
||||
for(unsigned tile = 0; tile < 32; tile++) { // 0-255
|
||||
unsigned nametable = cartridge.ciram_read((uint13)status.vaddr);
|
||||
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
|
||||
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
|
||||
raster_pixel(0);
|
||||
tick();
|
||||
|
@ -340,31 +370,31 @@ void PPU::raster_scanline() {
|
|||
raster_pixel(1);
|
||||
tick();
|
||||
|
||||
unsigned attribute = cartridge.ciram_read(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
if(scrolly() & 16) attribute >>= 4;
|
||||
if(scrollx() & 16) attribute >>= 2;
|
||||
raster_pixel(2);
|
||||
tick();
|
||||
|
||||
if(raster_enable()) {
|
||||
scrollx_increment();
|
||||
if(tile == 31) scrolly_increment();
|
||||
}
|
||||
scrollx_increment();
|
||||
if(tile == 31) scrolly_increment();
|
||||
raster_pixel(3);
|
||||
raster_sprite();
|
||||
tick();
|
||||
|
||||
unsigned tiledatalo = cartridge.chr_read(tileaddr + 0);
|
||||
unsigned tiledatalo = chr_load(tileaddr + 0);
|
||||
raster_pixel(4);
|
||||
tick();
|
||||
|
||||
raster_pixel(5);
|
||||
tick();
|
||||
|
||||
unsigned tiledatahi = cartridge.chr_read(tileaddr + 8);
|
||||
unsigned tiledatahi = chr_load(tileaddr + 8);
|
||||
raster_pixel(6);
|
||||
tick();
|
||||
|
||||
raster_pixel(7);
|
||||
raster_sprite();
|
||||
tick();
|
||||
|
||||
raster.nametable = (raster.nametable << 8) | nametable;
|
||||
|
@ -373,54 +403,32 @@ void PPU::raster_scanline() {
|
|||
raster.tiledatahi = (raster.tiledatahi << 8) | tiledatahi;
|
||||
}
|
||||
|
||||
for(unsigned n = 0; n < 8; n++) {
|
||||
raster.oam[n].id = 64;
|
||||
raster.oam[n].tiledatalo = 0;
|
||||
raster.oam[n].tiledatahi = 0;
|
||||
}
|
||||
|
||||
//should occur every 4 cycles during main screen rendering
|
||||
unsigned counter = 0;
|
||||
unsigned sprite_height = status.sprite_size ? 16 : 8;
|
||||
if(status.sprite_enable) for(unsigned n = 0; n < 64; n++) {
|
||||
unsigned y = ly - oam[(n * 4) + 0];
|
||||
if(y >= sprite_height) continue;
|
||||
if(counter == 8) {
|
||||
status.sprite_overflow = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
raster.oam[counter].id = n;
|
||||
raster.oam[counter].y = y;
|
||||
raster.oam[counter].tile = oam[(n * 4) + 1];
|
||||
raster.oam[counter].attr = oam[(n * 4) + 2];
|
||||
raster.oam[counter].x = oam[(n * 4) + 3];
|
||||
counter++;
|
||||
}
|
||||
for(unsigned n = 0; n < 8; n++) raster.oam[n] = raster.soam[n];
|
||||
|
||||
for(unsigned sprite = 0; sprite < 8; sprite++) { //256-319
|
||||
unsigned nametable = cartridge.ciram_read((uint13)status.vaddr);
|
||||
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
|
||||
tick();
|
||||
|
||||
if(raster_enable() && sprite == 0) status.vaddr = (status.vaddr & 0x7be0) | (status.taddr & 0x041f); //257
|
||||
tick();
|
||||
|
||||
unsigned attribute = cartridge.ciram_read(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
unsigned tileaddr = (sprite_height == 8)
|
||||
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
unsigned tileaddr = (sprite_height() == 8)
|
||||
? status.sprite_addr + raster.oam[sprite].tile * 16
|
||||
: ((raster.oam[sprite].tile & ~1) * 16) + ((raster.oam[sprite].tile & 1) * 0x1000);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
unsigned spritey = raster.oam[sprite].y;
|
||||
if(raster.oam[sprite].attr & 0x80) spritey ^= (sprite_height - 1);
|
||||
if(spritey & 8) spritey += 8;
|
||||
if(raster.oam[sprite].attr & 0x80) spritey ^= (sprite_height() - 1);
|
||||
tileaddr += spritey + (spritey & 8);
|
||||
if(raster.oam[sprite].id == 64) tileaddr = status.sprite_addr;
|
||||
|
||||
raster.oam[sprite].tiledatalo = cartridge.chr_read(tileaddr + spritey + 0);
|
||||
raster.oam[sprite].tiledatalo = chr_load(tileaddr + 0);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
raster.oam[sprite].tiledatahi = cartridge.chr_read(tileaddr + spritey + 8);
|
||||
raster.oam[sprite].tiledatahi = chr_load(tileaddr + 8);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
|
@ -428,26 +436,24 @@ void PPU::raster_scanline() {
|
|||
}
|
||||
|
||||
for(unsigned tile = 0; tile < 2; tile++) { //320-335
|
||||
unsigned nametable = cartridge.ciram_read((uint13)status.vaddr & 0x1fff);
|
||||
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
|
||||
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
unsigned attribute = cartridge.ciram_read(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
if(scrolly() & 16) attribute >>= 4;
|
||||
if(scrollx() & 16) attribute >>= 2;
|
||||
tick();
|
||||
|
||||
if(raster_enable()) {
|
||||
scrollx_increment();
|
||||
}
|
||||
scrollx_increment();
|
||||
tick();
|
||||
|
||||
unsigned tiledatalo = cartridge.chr_read(tileaddr + 0);
|
||||
unsigned tiledatalo = chr_load(tileaddr + 0);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
unsigned tiledatahi = cartridge.chr_read(tileaddr + 8);
|
||||
unsigned tiledatahi = chr_load(tileaddr + 8);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
|
@ -458,11 +464,11 @@ void PPU::raster_scanline() {
|
|||
}
|
||||
|
||||
//336-339
|
||||
unsigned nametable = cartridge.ciram_read((uint13)status.vaddr & 0x1fff);
|
||||
unsigned nametable = ciram_load(status.vaddr & 0x0fff);
|
||||
tick();
|
||||
tick();
|
||||
|
||||
unsigned attribute = cartridge.ciram_read(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
unsigned attribute = ciram_load(0x03c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
tick();
|
||||
tick();
|
||||
|
||||
|
|
|
@ -22,12 +22,17 @@ struct PPU : Processor {
|
|||
unsigned nametable_addr() const;
|
||||
unsigned scrollx() const;
|
||||
unsigned scrolly() const;
|
||||
unsigned sprite_height() const;
|
||||
|
||||
uint8 chr_load(uint16 addr);
|
||||
uint8 ciram_load(uint16 addr);
|
||||
|
||||
void ly_increment();
|
||||
void scrollx_increment();
|
||||
void scrolly_increment();
|
||||
|
||||
void raster_pixel(unsigned x);
|
||||
void raster_sprite();
|
||||
void raster_scanline();
|
||||
|
||||
struct Status {
|
||||
|
@ -43,7 +48,7 @@ struct PPU : Processor {
|
|||
|
||||
uint15 vaddr;
|
||||
uint15 taddr;
|
||||
uint8 xaddr;
|
||||
uint8 xaddr;
|
||||
|
||||
//$2000
|
||||
bool nmi_enable;
|
||||
|
@ -54,9 +59,7 @@ struct PPU : Processor {
|
|||
unsigned vram_increment;
|
||||
|
||||
//$2001
|
||||
bool intensify_blue;
|
||||
bool intensify_green;
|
||||
bool intensify_red;
|
||||
uint3 emphasis;
|
||||
bool sprite_enable;
|
||||
bool bg_enable;
|
||||
bool sprite_edge_enable;
|
||||
|
@ -78,6 +81,9 @@ struct PPU : Processor {
|
|||
uint16 tiledatalo;
|
||||
uint16 tiledatahi;
|
||||
|
||||
unsigned oam_iterator;
|
||||
unsigned oam_counter;
|
||||
|
||||
struct OAM {
|
||||
uint8 id;
|
||||
uint8 y;
|
||||
|
@ -87,11 +93,10 @@ struct PPU : Processor {
|
|||
|
||||
uint8 tiledatalo;
|
||||
uint8 tiledatahi;
|
||||
} oam[8];
|
||||
} oam[8], soam[8];
|
||||
} raster;
|
||||
|
||||
uint32 buffer[256 * 262];
|
||||
uint32 paletteRGB[64];
|
||||
uint16 buffer[256 * 262];
|
||||
uint8 ciram[2048];
|
||||
uint8 cgram[32];
|
||||
uint8 oam[256];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "082.10";
|
||||
static const char Version[] = "082.11";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
include $(gameboy)/Makefile
|
||||
|
||||
ui_objects := ui-main ui-utility
|
||||
ui_objects += ruby phoenix
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
ifeq ($(phoenix),gtk)
|
||||
phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`)
|
||||
link += `pkg-config --libs gtk+-2.0`
|
||||
else
|
||||
phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`)
|
||||
link += `pkg-config --libs QtCore QtGui`
|
||||
endif
|
||||
|
||||
ruby := video.glx video.xv video.sdl
|
||||
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.x
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
|
||||
else ifeq ($(platform),osx)
|
||||
phoenix_compile = $(call compile,-DPHOENIX_QT)
|
||||
link +=
|
||||
|
||||
ruby :=
|
||||
ruby += audio.openal
|
||||
ruby += input.carbon
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
|
||||
else ifeq ($(platform),win)
|
||||
phoenix_compile = $(call compile,-DPHOENIX_WINDOWS)
|
||||
link +=
|
||||
|
||||
ruby := video.direct3d video.wgl video.directdraw video.gdi
|
||||
ruby += audio.directsound audio.xaudio2
|
||||
ruby += input.rawinput input.directinput
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
|
||||
endif
|
||||
|
||||
# ruby
|
||||
rubyflags := $(if $(finstring .sdl,$(ruby)),`sdl-config --cflags`)
|
||||
|
||||
link += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
|
||||
link += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
|
||||
link += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
|
||||
link += $(if $(findstring video.glx,$(ruby)),-lGL)
|
||||
link += $(if $(findstring video.wgl,$(ruby)),-lopengl32)
|
||||
link += $(if $(findstring video.xv,$(ruby)),-lXv)
|
||||
link += $(if $(findstring audio.alsa,$(ruby)),-lasound)
|
||||
link += $(if $(findstring audio.ao,$(ruby)),-lao)
|
||||
link += $(if $(findstring audio.directsound,$(ruby)),-ldsound)
|
||||
link += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse)
|
||||
link += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple)
|
||||
link += $(if $(findstring audio.xaudio2,$(ruby)),-lole32)
|
||||
link += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid)
|
||||
link += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
|
||||
|
||||
rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
|
||||
|
||||
# rules
|
||||
objects := $(ui_objects) $(objects)
|
||||
objects := $(patsubst %,obj/%.o,$(objects))
|
||||
|
||||
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/*)
|
||||
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/utility/*)
|
||||
|
||||
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
|
||||
$(call compile,$(rubydef) $(rubyflags))
|
||||
|
||||
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
|
||||
$(phoenix_compile)
|
||||
|
||||
# targets
|
||||
build: $(objects)
|
||||
ifeq ($(platform),osx)
|
||||
test -d ../bgameboy.app || mkdir -p ../bgameboy.app/Contents/MacOS
|
||||
$(strip $(cpp) -o ../bgameboy.app/Contents/MacOS/bgameboy $(objects) $(link))
|
||||
else
|
||||
$(strip $(cpp) -o out/bgameboy $(objects) $(link))
|
||||
endif
|
||||
|
||||
install:
|
||||
ifeq ($(platform),x)
|
||||
install -D -m 755 out/bgameboy $(DESTDIR)$(prefix)/bin/bgameboy
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
ifeq ($(platform),x)
|
||||
rm $(DESTDIR)$(prefix)/bin/bgameboy
|
||||
endif
|
|
@ -1,34 +0,0 @@
|
|||
#include <nall/dsp.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.hpp>
|
||||
using namespace ruby;
|
||||
|
||||
#include <phoenix/phoenix.hpp>
|
||||
using namespace phoenix;
|
||||
|
||||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#include "interface.hpp"
|
||||
|
||||
#include "general/main-window.hpp"
|
||||
|
||||
#include "utility/utility.hpp"
|
||||
|
||||
struct Application {
|
||||
bool quit;
|
||||
|
||||
string proportionalFont;
|
||||
string proportionalFontBold;
|
||||
string monospaceFont;
|
||||
|
||||
void main(int argc, char **argv);
|
||||
};
|
||||
|
||||
extern nall::DSP dspaudio;
|
||||
extern Application application;
|
|
@ -1,134 +0,0 @@
|
|||
MainWindow mainWindow;
|
||||
|
||||
void MainWindow::create() {
|
||||
setTitle({ GameBoy::Info::Name, " v", GameBoy::Info::Version });
|
||||
setResizable(false);
|
||||
setMenuFont(application.proportionalFont);
|
||||
setWidgetFont(application.proportionalFont);
|
||||
setStatusFont(application.proportionalFontBold);
|
||||
|
||||
system.setText("System");
|
||||
append(system);
|
||||
|
||||
systemLoadCartridge.setText("Load Cartridge ...");
|
||||
system.append(systemLoadCartridge);
|
||||
|
||||
system.append(systemSeparator1);
|
||||
|
||||
systemPower.setText("Power Cycle");
|
||||
system.append(systemPower);
|
||||
|
||||
settings.setText("Settings");
|
||||
append(settings);
|
||||
|
||||
settingsVideoSync.setText("Synchronize Video");
|
||||
settingsVideoSync.setChecked(false);
|
||||
settings.append(settingsVideoSync);
|
||||
|
||||
settingsAudioSync.setText("Synchronize Audio");
|
||||
settingsAudioSync.setChecked(true);
|
||||
settings.append(settingsAudioSync);
|
||||
|
||||
tools.setText("Tools");
|
||||
append(tools);
|
||||
|
||||
toolsSaveState.setText("Save State");
|
||||
tools.append(toolsSaveState);
|
||||
|
||||
toolsSaveState1.setText("Slot 1");
|
||||
toolsSaveState.append(toolsSaveState1);
|
||||
|
||||
toolsSaveState2.setText("Slot 2");
|
||||
toolsSaveState.append(toolsSaveState2);
|
||||
|
||||
toolsSaveState3.setText("Slot 3");
|
||||
toolsSaveState.append(toolsSaveState3);
|
||||
|
||||
toolsSaveState4.setText("Slot 4");
|
||||
toolsSaveState.append(toolsSaveState4);
|
||||
|
||||
toolsSaveState5.setText("Slot 5");
|
||||
toolsSaveState.append(toolsSaveState5);
|
||||
|
||||
toolsLoadState.setText("Load State");
|
||||
tools.append(toolsLoadState);
|
||||
|
||||
toolsLoadState1.setText("Slot 1");
|
||||
toolsLoadState.append(toolsLoadState1);
|
||||
|
||||
toolsLoadState2.setText("Slot 2");
|
||||
toolsLoadState.append(toolsLoadState2);
|
||||
|
||||
toolsLoadState3.setText("Slot 3");
|
||||
toolsLoadState.append(toolsLoadState3);
|
||||
|
||||
toolsLoadState4.setText("Slot 4");
|
||||
toolsLoadState.append(toolsLoadState4);
|
||||
|
||||
toolsLoadState5.setText("Slot 5");
|
||||
toolsLoadState.append(toolsLoadState5);
|
||||
|
||||
tools.append(toolsSeparator1);
|
||||
|
||||
toolsTraceCPU.setText("Trace CPU");
|
||||
tools.append(toolsTraceCPU);
|
||||
|
||||
help.setText("Help");
|
||||
append(help);
|
||||
|
||||
helpAbout.setText("About ...");
|
||||
help.append(helpAbout);
|
||||
|
||||
layout.append(viewport, { 0, 0, 160 * 2, 144 * 2 });
|
||||
append(layout);
|
||||
setGeometry({ 128, 128, 160 * 2, 144 * 2 });
|
||||
|
||||
setMenuVisible(true);
|
||||
setStatusVisible(true);
|
||||
|
||||
onClose = []() {
|
||||
application.quit = true;
|
||||
};
|
||||
|
||||
systemLoadCartridge.onTick = []() {
|
||||
string filename = OS::fileLoad(mainWindow, "/media/sdb1/root/gameboy_images/", "Game Boy cartridges (*.gb,*.gbc)");
|
||||
if(filename != "") utility.loadCartridge(filename);
|
||||
};
|
||||
|
||||
systemPower.onTick = []() {
|
||||
if(GameBoy::cartridge.loaded()) GameBoy::system.power();
|
||||
};
|
||||
|
||||
settingsVideoSync.onTick = []() {
|
||||
video.set(Video::Synchronize, mainWindow.settingsVideoSync.checked());
|
||||
};
|
||||
|
||||
settingsAudioSync.onTick = []() {
|
||||
audio.set(Audio::Synchronize, mainWindow.settingsAudioSync.checked());
|
||||
};
|
||||
|
||||
toolsSaveState1.onTick = []() { utility.saveState(1); };
|
||||
toolsSaveState2.onTick = []() { utility.saveState(2); };
|
||||
toolsSaveState3.onTick = []() { utility.saveState(3); };
|
||||
toolsSaveState4.onTick = []() { utility.saveState(4); };
|
||||
toolsSaveState5.onTick = []() { utility.saveState(5); };
|
||||
|
||||
toolsLoadState1.onTick = []() { utility.loadState(1); };
|
||||
toolsLoadState2.onTick = []() { utility.loadState(2); };
|
||||
toolsLoadState3.onTick = []() { utility.loadState(3); };
|
||||
toolsLoadState4.onTick = []() { utility.loadState(4); };
|
||||
toolsLoadState5.onTick = []() { utility.loadState(5); };
|
||||
|
||||
toolsTraceCPU.onTick = []() {
|
||||
GameBoy::cpu.trace = mainWindow.toolsTraceCPU.checked();
|
||||
};
|
||||
|
||||
helpAbout.onTick = []() {
|
||||
MessageWindow::information(mainWindow, {
|
||||
"bgameboy\n\n",
|
||||
"Version: ", GameBoy::Info::Version, "\n",
|
||||
"Author: byuu\n",
|
||||
"Homepage: http://byuu.org/"
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
struct MainWindow : Window {
|
||||
Menu system;
|
||||
Item systemLoadCartridge;
|
||||
Separator systemSeparator1;
|
||||
Item systemPower;
|
||||
|
||||
Menu settings;
|
||||
CheckItem settingsVideoSync;
|
||||
CheckItem settingsAudioSync;
|
||||
|
||||
Menu tools;
|
||||
Menu toolsSaveState;
|
||||
Item toolsSaveState1;
|
||||
Item toolsSaveState2;
|
||||
Item toolsSaveState3;
|
||||
Item toolsSaveState4;
|
||||
Item toolsSaveState5;
|
||||
Menu toolsLoadState;
|
||||
Item toolsLoadState1;
|
||||
Item toolsLoadState2;
|
||||
Item toolsLoadState3;
|
||||
Item toolsLoadState4;
|
||||
Item toolsLoadState5;
|
||||
Separator toolsSeparator1;
|
||||
CheckItem toolsTraceCPU;
|
||||
|
||||
Menu help;
|
||||
Item helpAbout;
|
||||
|
||||
FixedLayout layout;
|
||||
Viewport viewport;
|
||||
|
||||
void create();
|
||||
};
|
||||
|
||||
extern MainWindow mainWindow;
|
|
@ -1,61 +0,0 @@
|
|||
Interface interface;
|
||||
|
||||
void Interface::video_refresh(const uint8_t *data) {
|
||||
uint32_t *buffer;
|
||||
unsigned pitch;
|
||||
if(video.lock(buffer, pitch, 160, 144)) {
|
||||
for(unsigned y = 0; y < 144; y++) {
|
||||
uint32_t *line = buffer + y * (pitch >> 2);
|
||||
const uint8_t *source = data + y * 160;
|
||||
for(unsigned x = 0; x < 160; x++) {
|
||||
uint32_t color = *source++;
|
||||
*line++ = (color << 16) | (color << 8) | (color << 0);
|
||||
}
|
||||
}
|
||||
video.unlock();
|
||||
video.refresh();
|
||||
}
|
||||
|
||||
static unsigned frameCounter = 0;
|
||||
static time_t timeCounter = time(0);
|
||||
|
||||
frameCounter++;
|
||||
time_t currentTime = time(0);
|
||||
if(currentTime != timeCounter) {
|
||||
timeCounter = currentTime;
|
||||
mainWindow.setStatusText({ "FPS: ", frameCounter });
|
||||
frameCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::audio_sample(int16_t center, int16_t lchannel, int16_t rchannel) {
|
||||
dspaudio.sample(lchannel, rchannel);
|
||||
while(dspaudio.pending()) {
|
||||
signed lsample, rsample;
|
||||
dspaudio.read(lsample, rsample);
|
||||
audio.sample(lsample, rsample);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::input_poll() {
|
||||
input.poll(inputState);
|
||||
}
|
||||
|
||||
bool Interface::input_poll(unsigned id) {
|
||||
switch((GameBoy::Input)id) {
|
||||
case GameBoy::Input::Up: return inputState[keyboard(0)[Keyboard::Up]];
|
||||
case GameBoy::Input::Down: return inputState[keyboard(0)[Keyboard::Down]];
|
||||
case GameBoy::Input::Left: return inputState[keyboard(0)[Keyboard::Left]];
|
||||
case GameBoy::Input::Right: return inputState[keyboard(0)[Keyboard::Right]];
|
||||
case GameBoy::Input::B: return inputState[keyboard(0)[Keyboard::Z]];
|
||||
case GameBoy::Input::A: return inputState[keyboard(0)[Keyboard::X]];
|
||||
case GameBoy::Input::Select: return inputState[keyboard(0)[Keyboard::Apostrophe]];
|
||||
case GameBoy::Input::Start: return inputState[keyboard(0)[Keyboard::Return]];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Interface::message(const string &text) {
|
||||
MessageWindow::information(mainWindow, text);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
struct Interface : public GameBoy::Interface {
|
||||
int16_t inputState[Scancode::Limit];
|
||||
|
||||
void video_refresh(const uint8_t *data);
|
||||
void audio_sample(int16_t center, int16_t left, int16_t right);
|
||||
void input_poll();
|
||||
bool input_poll(unsigned id);
|
||||
|
||||
void message(const string &text);
|
||||
};
|
||||
|
||||
extern Interface interface;
|
|
@ -1,78 +0,0 @@
|
|||
#include "base.hpp"
|
||||
nall::DSP dspaudio;
|
||||
Application application;
|
||||
|
||||
#include "interface.cpp"
|
||||
|
||||
#include "general/main-window.cpp"
|
||||
|
||||
void Application::main(int argc, char **argv) {
|
||||
quit = false;
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
proportionalFont = "Tahoma, 8";
|
||||
proportionalFontBold = "Tahoma, 8, Bold";
|
||||
monospaceFont = "Lucida Console, 8";
|
||||
#else
|
||||
proportionalFont = "Sans, 8";
|
||||
proportionalFontBold = "Sans, 8, Bold";
|
||||
monospaceFont = "Liberation Mono, 8";
|
||||
#endif
|
||||
|
||||
mainWindow.create();
|
||||
mainWindow.setVisible();
|
||||
OS::processEvents();
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
video.driver("Direct3D");
|
||||
#else
|
||||
video.driver("OpenGL");
|
||||
#endif
|
||||
video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||
video.set(Video::Synchronize, false);
|
||||
video.set(Video::Filter, (unsigned)0);
|
||||
video.init();
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
audio.driver("XAudio2");
|
||||
#else
|
||||
audio.driver("ALSA");
|
||||
#endif
|
||||
audio.set(Audio::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||
audio.set(Audio::Synchronize, true);
|
||||
audio.set(Audio::Latency, 80u);
|
||||
audio.set(Audio::Frequency, 44100u);
|
||||
audio.init();
|
||||
|
||||
dspaudio.setPrecision(16);
|
||||
dspaudio.setVolume(1.0);
|
||||
dspaudio.setBalance(0.0);
|
||||
dspaudio.setFrequency(4194304.0);
|
||||
dspaudio.setResampler(DSP::Resampler::Average);
|
||||
dspaudio.setResamplerFrequency(44100.0);
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
input.driver("RawInput");
|
||||
#else
|
||||
input.driver("SDL");
|
||||
#endif
|
||||
input.set(Input::Handle, (uintptr_t)mainWindow.viewport.handle());
|
||||
input.init();
|
||||
|
||||
GameBoy::system.init(&interface);
|
||||
|
||||
while(quit == false) {
|
||||
OS::processEvents();
|
||||
|
||||
if(GameBoy::cartridge.loaded()) {
|
||||
do {
|
||||
GameBoy::system.run();
|
||||
} while(GameBoy::scheduler.exit_reason() != GameBoy::Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
application.main(argc, argv);
|
||||
return 0;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#include "../base.hpp"
|
||||
Utility utility;
|
||||
|
||||
void Utility::loadCartridge(const char *filename) {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode::read)) {
|
||||
unsigned size = fp.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
|
||||
cartridge.basename = nall::basename(filename);
|
||||
|
||||
GameBoyCartridge info(data, size);
|
||||
GameBoy::cartridge.load(info.xml, data, size);
|
||||
delete[] data;
|
||||
GameBoy::system.power();
|
||||
}
|
||||
}
|
||||
|
||||
bool Utility::saveState(unsigned slot) {
|
||||
GameBoy::system.runtosave();
|
||||
serializer s = GameBoy::system.serialize();
|
||||
|
||||
file fp;
|
||||
if(fp.open(string(cartridge.basename, "-", slot, ".bst"), file::mode::write)) {
|
||||
fp.write(s.data(), s.size());
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Utility::loadState(unsigned slot) {
|
||||
file fp;
|
||||
if(fp.open(string(cartridge.basename, "-", slot, ".bst"), file::mode::read)) {
|
||||
unsigned size = fp.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
serializer s(data, size);
|
||||
GameBoy::system.power();
|
||||
return GameBoy::system.unserialize(s);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
struct Utility {
|
||||
struct Cartridge {
|
||||
string basename;
|
||||
} cartridge;
|
||||
|
||||
void loadCartridge(const char *filename);
|
||||
bool saveState(unsigned slot);
|
||||
bool loadState(unsigned slot);
|
||||
};
|
||||
|
||||
extern Utility utility;
|
|
@ -26,17 +26,17 @@ void InterfaceNES::setCheatCodes(const lstring &list) {
|
|||
|
||||
//
|
||||
|
||||
void InterfaceNES::video_refresh(const uint32_t *data) {
|
||||
void InterfaceNES::video_refresh(const uint16_t *data) {
|
||||
interface->video_refresh();
|
||||
|
||||
uint32_t *output;
|
||||
unsigned outpitch;
|
||||
if(video.lock(output, outpitch, 256, 240)) {
|
||||
for(unsigned y = 0; y < 240; y++) {
|
||||
const uint32_t *sp = data + y * 256;
|
||||
const uint16_t *sp = data + y * 256;
|
||||
uint32_t *dp = output + y * (outpitch >> 2);
|
||||
for(unsigned x = 0; x < 256; x++) {
|
||||
*dp++ = *sp++;
|
||||
*dp++ = palette[*sp++];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,3 +70,38 @@ int16_t InterfaceNES::input_poll(bool port, unsigned device, unsigned id) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
InterfaceNES::InterfaceNES() {
|
||||
palette = {
|
||||
0x7c7c7c, 0x0000fc, 0x0000bc, 0x4428bc,
|
||||
0x940084, 0xa80020, 0xa81000, 0x881400,
|
||||
0x503000, 0x007800, 0x006800, 0x005800,
|
||||
0x004058, 0x000000, 0x000000, 0x000000,
|
||||
0xbcbcbc, 0x0078f8, 0x0058f8, 0x6844fc,
|
||||
0xd800cc, 0xe40058, 0xf83800, 0xe45c10,
|
||||
0xac7c00, 0x00b800, 0x00a800, 0x00a844,
|
||||
0x008888, 0x000000, 0x000000, 0x000000,
|
||||
0xf8f8f8, 0x3cbcfc, 0x6888fc, 0x9878f8,
|
||||
0xf878f8, 0xf85898, 0xf87858, 0xfca044,
|
||||
0xf8b800, 0xb8f818, 0x58d854, 0x58f898,
|
||||
0x00e8d8, 0x787878, 0x000000, 0x000000,
|
||||
0xfcfcfc, 0xa4e4fc, 0xb8b8b8, 0xd8d8f8,
|
||||
0xf8b8f8, 0xf8a4c0, 0xf0d0b0, 0xfce0a8,
|
||||
0xf8d878, 0xd8f878, 0xb8f8b8, 0xb8f8d8,
|
||||
0x00fcfc, 0xf8d8f8, 0x000000, 0x000000,
|
||||
};
|
||||
|
||||
for(unsigned e = 1; e < 8; e++) {
|
||||
static const double rfactor[8] = { 1.000, 1.239, 0.794, 1.019, 0.905, 1.023, 0.741, 0.750 };
|
||||
static const double gfactor[8] = { 1.000, 0.915, 1.086, 0.980, 1.026, 0.908, 0.987, 0.750 };
|
||||
static const double bfactor[8] = { 1.000, 0.743, 0.882, 0.653, 1.277, 0.979, 0.101, 0.750 };
|
||||
for(unsigned n = 0; n < 64; n++) {
|
||||
unsigned c = palette[n];
|
||||
uint8_t r = c >> 16, g = c >> 8, b = c >> 0;
|
||||
r = uclamp<8>((unsigned)(r * rfactor[e]));
|
||||
g = uclamp<8>((unsigned)(g * gfactor[e]));
|
||||
b = uclamp<8>((unsigned)(b * bfactor[e]));
|
||||
palette[e * 64 + n] = (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,12 @@ struct InterfaceNES : NES::Interface {
|
|||
|
||||
void setCheatCodes(const lstring &list);
|
||||
|
||||
void video_refresh(const uint32_t *data);
|
||||
void video_refresh(const uint16_t *data);
|
||||
void audio_sample(int16_t sample);
|
||||
int16_t input_poll(bool port, unsigned device, unsigned id);
|
||||
|
||||
InterfaceNES();
|
||||
|
||||
private:
|
||||
unsigned palette[512];
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue