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:
Tim Allen 2011-09-15 22:27:34 +10:00
parent 278cf8462c
commit cb3460a673
17 changed files with 151 additions and 605 deletions

View File

@ -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:;

View File

@ -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; }

View File

@ -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";
}
}

View File

@ -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();

View File

@ -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];

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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/"
});
};
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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];
};