diff --git a/bsnes/Makefile b/bsnes/Makefile index db90cf82..49099aea 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -94,6 +94,6 @@ clean: ui_clean -@$(call delete,*.manifest) archive-all: - tar -cjf bsnes.tar.bz2 data gameboy launcher libco nall obj out phoenix ruby snes ui Makefile cc.bat clean.bat sync.sh + tar -cjf bsnes.tar.bz2 data gameboy launcher libco nall obj out phoenix ruby snes ui ui-gameboy Makefile cc.bat clean.bat sync.sh help:; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 909b7f52..12b51e88 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "073.03"; + static const char Version[] = "073.04"; static const unsigned SerializerVersion = 16; } } diff --git a/bsnes/sync.sh b/bsnes/sync.sh index ecb9528d..8b43d96b 100755 --- a/bsnes/sync.sh +++ b/bsnes/sync.sh @@ -17,6 +17,3 @@ test -d phoenix/nall && rm -r phoenix/nall rm -r phoenix/test* rm -r phoenix/*.sh rm -r phoenix/*.bat - -test -d gameboy && rm -r gameboy -cp -r ../bgameboy/gameboy ./gameboy diff --git a/bsnes/ui-gameboy/Makefile b/bsnes/ui-gameboy/Makefile new file mode 100755 index 00000000..c7c9db80 --- /dev/null +++ b/bsnes/ui-gameboy/Makefile @@ -0,0 +1,71 @@ +ui_objects := ui-main ui-utility +ui_objects += ruby phoenix + +# platform +ifeq ($(platform),x) + phoenix_compile = $(call compile,-DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`) + link += `pkg-config --libs gtk+-2.0` +# phoenix_compile = $(call compile,-DPHOENIX_QT `pkg-config --cflags QtCore QtGui`) +# link += `pkg-config --libs QtCore QtGui` + + 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) + +obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/*); $(phoenix_compile) +obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/utility/*); $(phoenix_compile) + +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 +ui_build:; + +ui_clean:; diff --git a/bsnes/ui-gameboy/base.hpp b/bsnes/ui-gameboy/base.hpp new file mode 100755 index 00000000..34892c9e --- /dev/null +++ b/bsnes/ui-gameboy/base.hpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +using namespace nall; + +#include +using namespace ruby; + +#include +using namespace phoenix; + +#include + +#include "interface.hpp" + +#include "general/main-window.hpp" + +#include "utility/utility.hpp" + +struct Application { + bool quit; + + Font proportionalFont; + Font proportionalFontBold; + Font monospaceFont; + + void main(int argc, char **argv); +}; + +extern Application application; diff --git a/bsnes/ui-gameboy/general/main-window.cpp b/bsnes/ui-gameboy/general/main-window.cpp new file mode 100755 index 00000000..a93fa165 --- /dev/null +++ b/bsnes/ui-gameboy/general/main-window.cpp @@ -0,0 +1,83 @@ +MainWindow mainWindow; + +void MainWindow::create() { + Window::create(128, 128, 160 * 2, 144 * 2, { GameBoy::Info::Name, " v", GameBoy::Info::Version }); + setDefaultFont(application.proportionalFont); + setFont(application.proportionalFontBold); + + system.create(*this, "System"); + systemLoadCartridge.create(system, "Load Cartridge ..."); + systemSeparator1.create(system); + systemPower.create(system, "Power Cycle"); + + settings.create(*this, "Settings"); + settingsVideoSync.create(settings, "Synchronize Video"); + settingsVideoSync.setChecked(true); + + tools.create(*this, "Tools"); + toolsSaveState.create(tools, "Save State"); + toolsSaveState1.create(toolsSaveState, "Slot 1"); + toolsSaveState2.create(toolsSaveState, "Slot 2"); + toolsSaveState3.create(toolsSaveState, "Slot 3"); + toolsSaveState4.create(toolsSaveState, "Slot 4"); + toolsSaveState5.create(toolsSaveState, "Slot 5"); + toolsLoadState.create(tools, "Load State"); + toolsLoadState1.create(toolsLoadState, "Slot 1"); + toolsLoadState2.create(toolsLoadState, "Slot 2"); + toolsLoadState3.create(toolsLoadState, "Slot 3"); + toolsLoadState4.create(toolsLoadState, "Slot 4"); + toolsLoadState5.create(toolsLoadState, "Slot 5"); + toolsSeparator1.create(tools); + toolsTraceCPU.create(tools, "Trace CPU"); + + help.create(*this, "Help"); + helpAbout.create(help, "About ..."); + + viewport.create(*this, 0, 0, 160 * 2, 144 * 2); + + setMenuVisible(true); + setStatusVisible(true); + + onClose = []() { + application.quit = true; + return false; + }; + + systemLoadCartridge.onTick = []() { + string filename = OS::fileOpen(mainWindow, "Game Boy cartridges\t*.gb,*.gbc", "/media/sdb1/root/gameboy_images/"); + if(filename != "") utility.loadCartridge(filename); + }; + + systemPower.onTick = []() { + if(GameBoy::cartridge.loaded()) GameBoy::system.power(); + }; + + settingsVideoSync.onTick = []() { + video.set(Video::Synchronize, mainWindow.settingsVideoSync.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/" + }); + }; +} diff --git a/bsnes/ui-gameboy/general/main-window.hpp b/bsnes/ui-gameboy/general/main-window.hpp new file mode 100755 index 00000000..6d752ba1 --- /dev/null +++ b/bsnes/ui-gameboy/general/main-window.hpp @@ -0,0 +1,34 @@ +struct MainWindow : Window { + Menu system; + MenuItem systemLoadCartridge; + MenuSeparator systemSeparator1; + MenuItem systemPower; + + Menu settings; + MenuCheckItem settingsVideoSync; + + Menu tools; + Menu toolsSaveState; + MenuItem toolsSaveState1; + MenuItem toolsSaveState2; + MenuItem toolsSaveState3; + MenuItem toolsSaveState4; + MenuItem toolsSaveState5; + Menu toolsLoadState; + MenuItem toolsLoadState1; + MenuItem toolsLoadState2; + MenuItem toolsLoadState3; + MenuItem toolsLoadState4; + MenuItem toolsLoadState5; + MenuSeparator toolsSeparator1; + MenuCheckItem toolsTraceCPU; + + Menu help; + MenuItem helpAbout; + + Viewport viewport; + + void create(); +}; + +extern MainWindow mainWindow; diff --git a/bsnes/ui-gameboy/interface.cpp b/bsnes/ui-gameboy/interface.cpp new file mode 100755 index 00000000..4cda5ac3 --- /dev/null +++ b/bsnes/ui-gameboy/interface.cpp @@ -0,0 +1,55 @@ +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(signed left, signed right) { +} + +void Interface::input_poll() { + input.poll(inputState); +} + +bool Interface::input_poll(unsigned id) { + switch(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); +} diff --git a/bsnes/ui-gameboy/interface.hpp b/bsnes/ui-gameboy/interface.hpp new file mode 100755 index 00000000..d6910bb9 --- /dev/null +++ b/bsnes/ui-gameboy/interface.hpp @@ -0,0 +1,12 @@ +struct Interface : public GameBoy::Interface { + int16_t inputState[Scancode::Limit]; + + void video_refresh(const uint8_t *data); + void audio_sample(signed left, signed right); + void input_poll(); + bool input_poll(unsigned id); + + void message(const string &text); +}; + +extern Interface interface; diff --git a/bsnes/ui-gameboy/main.cpp b/bsnes/ui-gameboy/main.cpp new file mode 100755 index 00000000..b0162ff6 --- /dev/null +++ b/bsnes/ui-gameboy/main.cpp @@ -0,0 +1,59 @@ +#include "base.hpp" +Application application; + +#include "interface.cpp" + +#include "general/main-window.cpp" + +void Application::main(int argc, char **argv) { + quit = false; + + #if defined(PHOENIX_WINDOWS) + proportionalFont.create("Tahoma", 8); + proportionalFontBold.create("Tahoma", 8, Font::Style::Bold); + monospaceFont.create("Courier New", 8); + #else + proportionalFont.create("Sans", 8); + proportionalFontBold.create("Sans", 8, Font::Style::Bold); + monospaceFont.create("Liberation Mono", 8); + #endif + + mainWindow.create(); + mainWindow.setVisible(); + OS::run(); + + #if defined(PHOENIX_WINDOWS) + video.driver("Direct3D"); + #else + video.driver("OpenGL"); + #endif + video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle()); + video.set(Video::Synchronize, true); + video.set(Video::Filter, (unsigned)0); + video.init(); + + #if defined(PHOENIX_WINDOWS) + 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::run(); + + 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; +} diff --git a/bsnes/ui-gameboy/utility/utility.cpp b/bsnes/ui-gameboy/utility/utility.cpp new file mode 100755 index 00000000..39875d72 --- /dev/null +++ b/bsnes/ui-gameboy/utility/utility.cpp @@ -0,0 +1,48 @@ +#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); + print(cartridge.basename, "\n"); + + 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); + return GameBoy::system.unserialize(s); + } + + return false; +} diff --git a/bsnes/ui-gameboy/utility/utility.hpp b/bsnes/ui-gameboy/utility/utility.hpp new file mode 100755 index 00000000..f8f39a31 --- /dev/null +++ b/bsnes/ui-gameboy/utility/utility.hpp @@ -0,0 +1,11 @@ +struct Utility { + struct Cartridge { + string basename; + } cartridge; + + void loadCartridge(const char *filename); + bool saveState(unsigned slot); + bool loadState(unsigned slot); +}; + +extern Utility utility;