From 2330ed6e8c1459a7409f47bf5d42c2475618b746 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 30 Dec 2010 18:18:47 +1100 Subject: [PATCH] Update to release v000r04. byuu says: [screenshot of the Tetris title screen] Less than fourty-eight hours after starting on this. I guess you weren't kidding, Exophase. --- gameboy/cpu/core/core.cpp | 4 +- gameboy/cpu/cpu.cpp | 72 ++++++++++++++++- gameboy/cpu/cpu.hpp | 37 +++++++++ gameboy/cpu/mmio/mmio.cpp | 110 ++++++++++++++++++++++++++ gameboy/cpu/timing/timing.cpp | 62 ++++++++++++--- gameboy/cpu/timing/timing.hpp | 6 +- gameboy/gameboy.hpp | 2 +- gameboy/lcd/lcd.cpp | 108 ++++++++++++++++++++++++- gameboy/lcd/lcd.hpp | 55 ++++++++++++- gameboy/lcd/mmio/mmio.cpp | 145 ++++++++++++++++++++++++++++++++-- gameboy/system/system.hpp | 4 + ui/base.hpp | 7 ++ ui/general/main-window.cpp | 10 ++- ui/interface.cpp | 37 +++++++++ ui/interface.hpp | 2 + ui/main.cpp | 34 +++++--- 16 files changed, 654 insertions(+), 41 deletions(-) diff --git a/gameboy/cpu/core/core.cpp b/gameboy/cpu/core/core.cpp index b1eb86cb..b401ec18 100755 --- a/gameboy/cpu/core/core.cpp +++ b/gameboy/cpu/core/core.cpp @@ -324,7 +324,7 @@ void CPU::op_rlca() { void CPU::op_rla() { bool c = r[A] & 0x80; - r[A] = (r[A] << 1) | (c << 0); + r[A] = (r[A] << 1) | (r.f.c << 0); r.f.z = 0; r.f.n = 0; r.f.h = 0; @@ -341,7 +341,7 @@ void CPU::op_rrca() { void CPU::op_rra() { bool c = r[A] & 0x01; - r[A] = (r[A] >> 1) | (c << 7); + r[A] = (r[A] >> 1) | (r.f.c << 7); r.f.z = 0; r.f.n = 0; r.f.h = 0; diff --git a/gameboy/cpu/cpu.cpp b/gameboy/cpu/cpu.cpp index 0589f0a4..5a0bc001 100755 --- a/gameboy/cpu/cpu.cpp +++ b/gameboy/cpu/cpu.cpp @@ -15,15 +15,57 @@ void CPU::Main() { void CPU::main() { while(true) { //print(disassemble(r[PC]), "\n"); + interrupt_test(); uint8 opcode = op_read(r[PC]++); (this->*opcode_table[opcode])(); } } +void CPU::interrupt_test() { + if(status.ime) { + if(status.interrupt_request_vblank && status.interrupt_enable_vblank) { + status.interrupt_request_vblank = 0; + return interrupt_exec(0x0040); + } + + if(status.interrupt_request_stat && status.interrupt_enable_stat) { + status.interrupt_request_stat = 0; + return interrupt_exec(0x0048); + } + + if(status.interrupt_request_timer && status.interrupt_enable_timer) { + status.interrupt_request_timer = 0; + return interrupt_exec(0x0050); + } + + if(status.interrupt_request_serial && status.interrupt_enable_serial) { + status.interrupt_request_serial = 0; + return interrupt_exec(0x0058); + } + + if(status.interrupt_request_joypad && status.interrupt_enable_joypad) { + status.interrupt_request_joypad = 0; + return interrupt_exec(0x0060); + } + } +} + +void CPU::interrupt_exec(uint16 pc) { + status.ime = 0; + op_write(--r[SP], r[PC] >> 8); + op_write(--r[SP], r[PC] >> 0); + r[PC] = pc; + op_io(); +} + void CPU::power() { for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror) - for(unsigned n = 0xff80; n <= 0xfffe; n++) bus.mmio[n] = this; //HRAM + for(unsigned n = 0xff00; n <= 0xff0f; n++) bus.mmio[n] = this; //MMIO + for(unsigned n = 0xff80; n <= 0xffff; n++) bus.mmio[n] = this; //HRAM+IE + + for(unsigned n = 0; n < 8192; n++) wram[n] = 0x00; + for(unsigned n = 0; n < 128; n++) hram[n] = 0x00; reset(); } @@ -39,6 +81,34 @@ void CPU::reset() { r[HL] = 0x0000; status.ime = 0; + status.timer0 = 0; + status.timer1 = 0; + status.timer2 = 0; + status.timer3 = 0; + + status.p15 = 0; + status.p14 = 0; + + status.div = 0; + + status.tima = 0; + + status.tma = 0; + + status.timer_enable = 0; + status.timer_clock = 0; + + status.interrupt_request_joypad = 0; + status.interrupt_request_serial = 0; + status.interrupt_request_timer = 0; + status.interrupt_request_stat = 0; + status.interrupt_request_vblank = 0; + + status.interrupt_enable_joypad = 0; + status.interrupt_enable_serial = 0; + status.interrupt_enable_timer = 0; + status.interrupt_enable_stat = 0; + status.interrupt_enable_vblank = 0; } CPU::CPU() { diff --git a/gameboy/cpu/cpu.hpp b/gameboy/cpu/cpu.hpp index d969145a..dc66e90f 100755 --- a/gameboy/cpu/cpu.hpp +++ b/gameboy/cpu/cpu.hpp @@ -5,6 +5,41 @@ struct CPU : Processor, MMIO { struct Status { bool ime; + unsigned timer0; + unsigned timer1; + unsigned timer2; + unsigned timer3; + + //$ff00 JOYP + bool p15; + bool p14; + + //$ff04 DIV + uint8 div; + + //$ff05 TIMA + uint8 tima; + + //$ff06 TMA + uint8 tma; + + //$ff07 TAC + bool timer_enable; + unsigned timer_clock; + + //$ff0f IF + bool interrupt_request_joypad; + bool interrupt_request_serial; + bool interrupt_request_timer; + bool interrupt_request_stat; + bool interrupt_request_vblank; + + //$ffff IE + bool interrupt_enable_joypad; + bool interrupt_enable_serial; + bool interrupt_enable_timer; + bool interrupt_enable_stat; + bool interrupt_enable_vblank; } status; uint8 wram[8192]; @@ -12,6 +47,8 @@ struct CPU : Processor, MMIO { static void Main(); void main(); + void interrupt_test(); + void interrupt_exec(uint16 pc); void power(); void reset(); CPU(); diff --git a/gameboy/cpu/mmio/mmio.cpp b/gameboy/cpu/mmio/mmio.cpp index edb7b8f6..4d6322b0 100755 --- a/gameboy/cpu/mmio/mmio.cpp +++ b/gameboy/cpu/mmio/mmio.cpp @@ -4,12 +4,122 @@ uint8 CPU::mmio_read(uint16 addr) { if(addr >= 0xc000 && addr <= 0xdfff) return wram[addr & 0x1fff]; if(addr >= 0xe000 && addr <= 0xfdff) return wram[addr & 0x1fff]; if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f]; + + if(addr == 0xff00) { //JOYP + unsigned keys = 0x0f; + + if(status.p15 == 0 && status.p14 == 1) { + keys = !system.interface->input_poll((unsigned)Input::Down) << 3; + keys |= !system.interface->input_poll((unsigned)Input::Up) << 2; + keys |= !system.interface->input_poll((unsigned)Input::Left) << 1; + keys |= !system.interface->input_poll((unsigned)Input::Right) << 0; + } + + if(status.p15 == 1 && status.p14 == 0) { + keys = !system.interface->input_poll((unsigned)Input::Start) << 3; + keys |= !system.interface->input_poll((unsigned)Input::Select) << 2; + keys |= !system.interface->input_poll((unsigned)Input::B) << 1; + keys |= !system.interface->input_poll((unsigned)Input::A) << 0; + } + + return (status.p15 << 5) + | (status.p14 << 4) + | (keys << 0); + } + + if(addr == 0xff04) { //DIV + return status.div; + } + + if(addr == 0xff05) { //TIMA + return status.tima; + } + + if(addr == 0xff06) { //TMA + return status.tma; + } + + if(addr == 0xff07) { //TAC + return (status.timer_enable << 2) + | (status.timer_clock << 0); + } + + if(addr == 0xff0f) { //IF + return (status.interrupt_request_joypad << 4) + | (status.interrupt_request_serial << 3) + | (status.interrupt_request_timer << 2) + | (status.interrupt_request_stat << 1) + | (status.interrupt_request_vblank << 0); + } + + if(addr == 0xffff) { //IE + return (status.interrupt_enable_joypad << 4) + | (status.interrupt_enable_serial << 3) + | (status.interrupt_enable_timer << 2) + | (status.interrupt_enable_stat << 1) + | (status.interrupt_enable_vblank << 0); + } + + return 0x00; } void CPU::mmio_write(uint16 addr, uint8 data) { if(addr >= 0xc000 && addr <= 0xdfff) { wram[addr & 0x1fff] = data; return; } if(addr >= 0xe000 && addr <= 0xfdff) { wram[addr & 0x1fff] = data; return; } if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; } + + if(addr == 0xff00) { //JOYP + status.p15 = data & 0x20; + status.p14 = data & 0x10; + return; + } + + if(addr == 0xff01) { //SB + return; + } + + if(addr == 0xff02) { //SC + return; + } + + if(addr == 0xff04) { //DIV + status.div = 0; + return; + } + + if(addr == 0xff05) { //TIMA + status.tima = data; + return; + } + + if(addr == 0xff06) { //TMA + status.tma = data; + return; + } + + if(addr == 0xff07) { //TAC + status.timer_enable = data & 0x04; + status.timer_clock = data & 0x03; + return; + } + + if(addr == 0xff0f) { //IF + status.interrupt_request_joypad = data & 0x10; + status.interrupt_request_serial = data & 0x08; + status.interrupt_request_timer = data & 0x04; + status.interrupt_request_stat = data & 0x02; + status.interrupt_request_vblank = data & 0x01; + return; + } + + if(addr == 0xffff) { //IE + status.interrupt_enable_joypad = data & 0x10; + status.interrupt_enable_serial = data & 0x08; + status.interrupt_enable_timer = data & 0x04; + status.interrupt_enable_stat = data & 0x02; + status.interrupt_enable_vblank = data & 0x01; + return; + } } #endif diff --git a/gameboy/cpu/timing/timing.cpp b/gameboy/cpu/timing/timing.cpp index 7f7e8ef9..0d96e62e 100755 --- a/gameboy/cpu/timing/timing.cpp +++ b/gameboy/cpu/timing/timing.cpp @@ -3,26 +3,70 @@ // 456 clocks/scanline // 154 scanlines/frame +//4194304 / 4096 = 1024 +//4194304 / 262144 = 16 +//4194304 / 65536 = 64 +//4394304 / 16384 = 256 + #ifdef CPU_CPP #include "opcode.cpp" void CPU::add_clocks(unsigned clocks) { - clock += clocks; + status.timer0 += clocks; + if(status.timer0 >= 16) timer_stage0(); - if(clock >= 456) scanline(); + cpu.clock += clocks; + if(cpu.clock >= 0) co_switch(scheduler.active_thread = lcd.thread); } -void CPU::scanline() { - clock -= 456; +void CPU::timer_stage0() { //262144hz + if(status.timer_clock == 1) { + if(++status.tima == 0) { + status.tima = status.tma; + status.interrupt_request_timer = 1; + } + } - lcd.status.ly++; - if(lcd.status.ly >= 154) frame(); + status.timer0 -= 16; + if(++status.timer1 >= 4) timer_stage1(); } -void CPU::frame() { - lcd.status.ly -= 154; - scheduler.exit(); +void CPU::timer_stage1() { // 65536hz + if(status.timer_clock == 2) { + if(++status.tima == 0) { + status.tima = status.tma; + status.interrupt_request_timer = 1; + } + } + + status.timer1 -= 4; + if(++status.timer2 >= 4) timer_stage2(); +} + +void CPU::timer_stage2() { // 16384hz + if(status.timer_clock == 3) { + if(++status.tima == 0) { + status.tima = status.tma; + status.interrupt_request_timer = 1; + } + } + + status.div++; + + status.timer2 -= 4; + if(++status.timer3 >= 4) timer_stage3(); +} + +void CPU::timer_stage3() { // 4096hz + if(status.timer_clock == 0) { + if(++status.tima == 0) { + status.tima = status.tma; + status.interrupt_request_timer = 1; + } + } + + status.timer3 -= 4; } #endif diff --git a/gameboy/cpu/timing/timing.hpp b/gameboy/cpu/timing/timing.hpp index 89dbf7d8..7362f02e 100755 --- a/gameboy/cpu/timing/timing.hpp +++ b/gameboy/cpu/timing/timing.hpp @@ -1,6 +1,8 @@ void add_clocks(unsigned clocks); -void scanline(); -void frame(); +void timer_stage0(); +void timer_stage1(); +void timer_stage2(); +void timer_stage3(); //opcode.cpp void op_io(); diff --git a/gameboy/gameboy.hpp b/gameboy/gameboy.hpp index e6ba73a5..f51da8c0 100755 --- a/gameboy/gameboy.hpp +++ b/gameboy/gameboy.hpp @@ -5,7 +5,7 @@ namespace GameBoy { namespace Info { static const char Name[] = "bgameboy"; - static const char Version[] = "000.03"; + static const char Version[] = "000.04"; } } diff --git a/gameboy/lcd/lcd.cpp b/gameboy/lcd/lcd.cpp index fef0a795..11686b29 100755 --- a/gameboy/lcd/lcd.cpp +++ b/gameboy/lcd/lcd.cpp @@ -6,16 +6,120 @@ namespace GameBoy { #include "mmio/mmio.cpp" LCD lcd; +void LCD::Main() { + lcd.main(); +} + +void LCD::main() { + while(true) { + add_clocks(4); + } +} + +void LCD::add_clocks(unsigned clocks) { + status.lx += clocks; + if(status.lx >= 456) scanline(); + + cpu.clock -= clocks; + if(cpu.clock <= 0) co_switch(scheduler.active_thread = cpu.thread); +} + +void LCD::scanline() { + status.lx -= 456; + status.ly++; + + if(status.ly == 144) cpu.status.interrupt_request_vblank = 1; +//print("Vblank - ", cpu.status.ime, " - ", cpu.status.interrupt_enable_vblank, "\n"); } + if(status.ly == 154) frame(); + + if(status.ly < 144) render(); +} + +void LCD::frame() { + system.interface->video_refresh(screen); + system.interface->input_poll(); + + status.ly = 0; + scheduler.exit(); +} + +void LCD::render() { + uint8_t *output = screen + status.ly * 160; + uint8 y = status.ly + status.scy; + uint16 tmaddr = (status.bg_tilemap_select == 0 ? 0x1800 : 0x1c00); + tmaddr += (y >> 3) * 32; + tmaddr += (status.scx >> 3); + + for(unsigned t = 0; t < 20; t++) { + unsigned tdaddr; + if(status.bg_tiledata_select == 0) { + tdaddr = 0x1000 + (int8)vram[tmaddr + t] * 16; + } else { + tdaddr = 0x0000 + vram[tmaddr + t] * 16; + } + tdaddr += (status.ly & 7) * 2; + + uint8 d0 = vram[tdaddr + 0]; + uint8 d1 = vram[tdaddr + 1]; + + for(unsigned x = 0; x < 8; x++) { + uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6); + d0 <<= 1, d1 <<= 1; + *output++ = (3 - status.bgp[palette]) * 0x55; + } + } +} + void LCD::power() { - for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this; //VRAM - for(unsigned n = 0xff40; n <= 0xff4f; n++) bus.mmio[n] = this; //MMIO + for(unsigned n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM + for(unsigned n = 0xff40; n <= 0xff4b; n++) bus.mmio[n] = this; //MMIO for(unsigned n = 0xfe00; n <= 0xfe9f; n++) bus.mmio[n] = this; //OAM + for(unsigned n = 0; n < 8192; n++) vram[n] = 0x00; + for(unsigned n = 0; n < 160; n++) oam [n] = 0x00; + reset(); } void LCD::reset() { + create(Main, 4 * 1024 * 1024); + for(unsigned n = 0; n < 160 * 144; n++) screen[n] = 0x00; + + status.lx = 0; + + status.display_enable = 0; + status.window_tilemap_select = 0; + status.window_display_enable = 0; + status.bg_tiledata_select = 0; + status.bg_tilemap_select = 0; + status.obj_size = 0; + status.obj_enable = 0; + status.bg_display = 0; + + status.interrupt_lyc = 0; + status.interrupt_oam = 0; + status.interrupt_vblank = 0; + status.interrupt_hblank = 0; + status.coincidence = 0; + status.mode = 0; + + status.scy = 0; + + status.scx = 0; + status.ly = 0; + + status.lyc = 0; + + for(unsigned n = 0; n < 4; n++) { + status.bgp[n] = n; + status.obp0[n] = n; + status.obp1[n] = n; + } + + status.wy = 0; + + status.wx = 0; } } diff --git a/gameboy/lcd/lcd.hpp b/gameboy/lcd/lcd.hpp index 07a2ae16..70056c8c 100755 --- a/gameboy/lcd/lcd.hpp +++ b/gameboy/lcd/lcd.hpp @@ -2,12 +2,65 @@ struct LCD : Processor, MMIO { #include "mmio/mmio.hpp" struct Status { - unsigned ly; + unsigned lx; + + //$ff40 LCDC + bool display_enable; + bool window_tilemap_select; + bool window_display_enable; + bool bg_tiledata_select; + bool bg_tilemap_select; + bool obj_size; + bool obj_enable; + bool bg_display; + + //$ff41 STAT + bool interrupt_lyc; + bool interrupt_oam; + bool interrupt_vblank; + bool interrupt_hblank; + bool coincidence; + unsigned mode; + + //$ff42 SCY + uint8 scy; + + //$ff43 SCX + uint8 scx; + + //$ff44 LY + uint8 ly; + + //$ff45 LYC + uint8 lyc; + + //$ff47 BGP + uint8 bgp[4]; + + //$ff48 OBP0 + uint8 obp0[4]; + + //$ff49 OBP1 + uint8 obp1[4]; + + //$ff4a WY + uint8 wy; + + //$ff4b WX + uint8 wx; } status; + uint8 screen[160 * 144]; uint8 vram[8192]; uint8 oam[160]; + static void Main(); + void main(); + void add_clocks(unsigned clocks); + void scanline(); + void frame(); + void render(); + void power(); void reset(); }; diff --git a/gameboy/lcd/mmio/mmio.cpp b/gameboy/lcd/mmio/mmio.cpp index 51aeb634..bff31ada 100755 --- a/gameboy/lcd/mmio/mmio.cpp +++ b/gameboy/lcd/mmio/mmio.cpp @@ -1,26 +1,159 @@ #ifdef LCD_CPP uint8 LCD::mmio_read(uint16 addr) { - if(addr >= 0xa000 && addr <= 0xbfff) return vram[addr & 0x1fff]; + if(addr >= 0x8000 && addr <= 0x9fff) return vram[addr & 0x1fff]; if(addr >= 0xfe00 && addr <= 0xfe9f) return oam[addr & 0xff]; - //LY - if(addr == 0xff44) { + if(addr == 0xff40) { //LCDC + return (status.display_enable << 7) + | (status.window_tilemap_select << 6) + | (status.window_display_enable << 5) + | (status.bg_tiledata_select << 4) + | (status.bg_tilemap_select << 3) + | (status.obj_size << 2) + | (status.obj_enable << 1) + | (status.bg_display << 0); + } + + if(addr == 0xff41) { //STAT + return (status.interrupt_lyc << 6) + | (status.interrupt_oam << 5) + | (status.interrupt_vblank << 4) + | (status.interrupt_hblank << 3) + | (status.coincidence << 2) + | (status.mode << 0); + } + + if(addr == 0xff42) { //SCY + return status.scy; + } + + if(addr == 0xff43) { //SCX + return status.scx; + } + + if(addr == 0xff44) { //LY return status.ly; } + if(addr == 0xff45) { //LYC + return status.lyc; + } + + if(addr == 0xff47) { //BGP + return (status.bgp[3] << 6) + | (status.bgp[2] << 4) + | (status.bgp[1] << 2) + | (status.bgp[0] << 0); + } + + if(addr == 0xff48) { //OBP0 + return (status.obp0[3] << 6) + | (status.obp0[2] << 4) + | (status.obp0[1] << 2) + | (status.obp0[0] << 0); + } + + if(addr == 0xff49) { //OBP1 + return (status.obp1[3] << 6) + | (status.obp1[2] << 4) + | (status.obp1[1] << 2) + | (status.obp1[0] << 0); + } + + if(addr == 0xff4a) { //WY + return status.wy; + } + + if(addr == 0xff4b) { //WX + return status.wx; + } + return 0x00; } void LCD::mmio_write(uint16 addr, uint8 data) { - if(addr >= 0xa000 && addr <= 0xbfff) { vram[addr & 0x1fff] = data; return; } + if(addr >= 0x8000 && addr <= 0x9fff) { vram[addr & 0x1fff] = data; return; } if(addr >= 0xfe00 && addr <= 0xfe9f) { oam[addr & 0xff] = data; return; } - //LY - if(addr == 0xff44) { + if(addr == 0xff40) { //LCDC + status.display_enable = data & 0x80; + status.window_tilemap_select = data & 0x40; + status.window_display_enable = data & 0x20; + status.bg_tiledata_select = data & 0x10; + status.bg_tilemap_select = data & 0x08; + status.obj_size = data & 0x04; + status.obj_enable = data & 0x02; + status.bg_display = data & 0x01; + return; + } + + if(addr == 0xff41) { //STAT + status.interrupt_lyc = data & 0x40; + status.interrupt_oam = data & 0x20; + status.interrupt_vblank = data & 0x10; + status.interrupt_hblank = data & 0x08; + return; + } + + if(addr == 0xff42) { //SCY + status.scy = data; + return; + } + + if(addr == 0xff43) { //SCX + status.scx = data; + return; + } + + if(addr == 0xff44) { //LY status.ly = 0; return; } + + if(addr == 0xff45) { //LYC + status.lyc = data; + return; + } + + if(addr == 0xff46) { //DMA + //TODO + return; + } + + if(addr == 0xff47) { //BGP + status.bgp[3] = (data >> 6) & 3; + status.bgp[2] = (data >> 4) & 3; + status.bgp[1] = (data >> 2) & 3; + status.bgp[0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff48) { //OBP0 + status.obp0[3] = (data >> 6) & 3; + status.obp0[2] = (data >> 4) & 3; + status.obp0[1] = (data >> 2) & 3; + status.obp0[0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff49) { //OBP1 + status.obp1[3] = (data >> 6) & 3; + status.obp1[2] = (data >> 4) & 3; + status.obp1[1] = (data >> 2) & 3; + status.obp1[0] = (data >> 0) & 3; + return; + } + + if(addr == 0xff4a) { //WY + status.wy = data; + return; + } + + if(addr == 0xff4b) { //WX + status.wx = data; + return; + } } #endif diff --git a/gameboy/system/system.hpp b/gameboy/system/system.hpp index ccc6c889..f9a6011c 100755 --- a/gameboy/system/system.hpp +++ b/gameboy/system/system.hpp @@ -1,5 +1,9 @@ class Interface; +enum class Input : unsigned { + Up, Down, Left, Right, B, A, Select, Start, +}; + class System { public: void init(Interface*); diff --git a/ui/base.hpp b/ui/base.hpp index 323331fb..66eb11ad 100755 --- a/ui/base.hpp +++ b/ui/base.hpp @@ -4,6 +4,9 @@ #include using namespace nall; +#include +using namespace ruby; + #include using namespace phoenix; @@ -18,6 +21,10 @@ using namespace phoenix; struct Application { bool quit; + Font proportionalFont; + Font proportionalFontBold; + Font monospaceFont; + void main(int argc, char **argv); }; diff --git a/ui/general/main-window.cpp b/ui/general/main-window.cpp index fb08eac2..7aa7541e 100755 --- a/ui/general/main-window.cpp +++ b/ui/general/main-window.cpp @@ -1,7 +1,9 @@ MainWindow mainWindow; void MainWindow::create() { - Window::create(128, 128, 160 * 3, 144 * 3, { GameBoy::Info::Name, " v", GameBoy::Info::Version }); + 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 ..."); @@ -12,15 +14,15 @@ void MainWindow::create() { systemReset.setEnabled(false); settings.create(*this, "Settings"); - settings.setEnabled(false); +//settings.setEnabled(false); tools.create(*this, "Tools"); - tools.setEnabled(false); +//tools.setEnabled(false); help.create(*this, "Help"); helpAbout.create(help, "About ..."); - viewport.create(*this, 0, 0, 160 * 3, 144 * 3); + viewport.create(*this, 0, 0, 160 * 2, 144 * 2); setMenuVisible(true); setStatusVisible(true); diff --git a/ui/interface.cpp b/ui/interface.cpp index dd28990d..4cda5ac3 100755 --- a/ui/interface.cpp +++ b/ui/interface.cpp @@ -1,15 +1,52 @@ 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; } diff --git a/ui/interface.hpp b/ui/interface.hpp index e33902d5..d6910bb9 100755 --- a/ui/interface.hpp +++ b/ui/interface.hpp @@ -1,4 +1,6 @@ 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(); diff --git a/ui/main.cpp b/ui/main.cpp index 87deb7f4..6f65651e 100755 --- a/ui/main.cpp +++ b/ui/main.cpp @@ -8,34 +8,42 @@ Application application; void Application::main(int argc, char **argv) { quit = false; - mainWindow.create(); + #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(); + + video.driver("OpenGL"); + video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle()); + video.set(Video::Synchronize, false); + video.set(Video::Filter, (unsigned)0); + video.init(); + + input.driver("SDL"); + input.set(Input::Handle, (uintptr_t)mainWindow.viewport.handle()); + input.init(); GameBoy::system.init(&interface); - unsigned frameCounter = 0; - time_t timeCounter = time(0); - while(quit == false) { OS::run(); if(GameBoy::cartridge.loaded()) { GameBoy::system.run(); - - frameCounter++; - time_t currentTime = time(0); - if(currentTime != timeCounter) { - timeCounter = currentTime; - mainWindow.setStatusText({ "FPS: ", frameCounter }); - frameCounter = 0; - } } } } int main(int argc, char **argv) { application.main(argc, argv); - return 0; }