diff --git a/bsnes.cfg b/bsnes.cfg index 4d0ac23f..897d2416 100644 --- a/bsnes.cfg +++ b/bsnes.cfg @@ -1,9 +1,11 @@ -#[bsnes v0.007a configuration file] +#[bsnes v0.009 configuration file] #[video mode] -# 0: 256x224w -# 1: 512x448w -# 2: 960x720w +# 0: 256x224w +# 1: 512x448w +# 2: 960x720w +# 3: 640x480f +# 4: 1024x768f video.mode = 1 #[video memory type] @@ -19,9 +21,16 @@ video.mode = 1 # way to guarantee that the output image will not be # filtered. video.use_vram = true -#video.use_vram = false + +#[color curve] +# gives a more NTSC TV-style feel to the color palette +# by darkening the image contrast. +video.color_curve = enabled #[show fps] # true: show fps in titlebar # false: do not show fps in titlebar -#gui.show_fps = false +gui.show_fps = true + +#[wait for vertical retrace] +video.vblank = false diff --git a/bsnes_g2.exe b/bsnes_g2.exe index f18dd6d8..2681758f 100644 Binary files a/bsnes_g2.exe and b/bsnes_g2.exe differ diff --git a/src/clock/bclock/bclock.h b/src/clock/bclock/bclock.h index 89b32d2b..4de562e6 100644 --- a/src/clock/bclock/bclock.h +++ b/src/clock/bclock/bclock.h @@ -5,9 +5,9 @@ bool changed, notify_ppu; uint8 count, new_count, pos; }frameskip; bool signal_scanline, signal_frame; - void frameskip_update_status(); - void inc_vcounter(); - void dram_refresh_test(); + inline void frameskip_update_status(); + inline void inc_vcounter(); + inline void dram_refresh_test(); public: struct { @@ -23,14 +23,14 @@ public: uint32 pos, last_pos; }cc2; - void set_frameskip(uint8 fs); + inline void set_frameskip(uint8 fs); - void add_cc1_cycles(uint32 cycles); - void add_cc2_cycles(uint32 cycles); - void sync(); - void run(); - void power(); - void reset(); + inline void add_cc1_cycles(uint32 cycles); + inline void add_cc2_cycles(uint32 cycles); + inline void sync(); + inline void run(); + inline void power(); + inline void reset(); bClock(); ~bClock(); diff --git a/src/cpu/bcpu/bcpu.cpp b/src/cpu/bcpu/bcpu.cpp index 9552a471..410300e2 100644 --- a/src/cpu/bcpu/bcpu.cpp +++ b/src/cpu/bcpu/bcpu.cpp @@ -89,7 +89,7 @@ uint16 v, h, hc, vs; //IRQ test if(!regs.p.i) { - if(status.virq_enabled == true && status.virq_enabled == true) { + if(status.virq_enabled == true && status.hirq_enabled == true) { if(v == status.virq_pos && h >= status.hirq_pos && status.irq_pin == 1) { status.irq_triggered = true; status.irq_pin = 0; @@ -148,6 +148,7 @@ void bCPU::frame() { status.nmi_triggered = false; status.r4210_read = false; + status.irq_triggered = false; status.irq_pin = 1; dma->hdma_initialize(); diff --git a/src/cpu/bcpu/bcpu.h b/src/cpu/bcpu/bcpu.h index 8bbcb791..4570bf8a 100644 --- a/src/cpu/bcpu/bcpu.h +++ b/src/cpu/bcpu/bcpu.h @@ -165,19 +165,19 @@ struct { void mmio_w43x6(uint8 value, uint8 i); void mmio_w43x7(uint8 value, uint8 i); - void exec_opcode(); + inline void exec_opcode(); - uint8 op_read (); - uint8 op_read (uint8 mode, uint32 addr); - void op_write(uint8 mode, uint32 addr, uint8 value); - uint8 stack_read (); - void stack_write(uint8 value); + inline uint8 op_read (); + inline uint8 op_read (uint8 mode, uint32 addr); + inline void op_write(uint8 mode, uint32 addr, uint8 value); + inline uint8 stack_read (); + inline void stack_write(uint8 value); //cpu extra-cycle conditions - void cpu_c2(); - void cpu_c4(uint16 a, uint16 b); - void cpu_c6(uint16 a); - void cpu_io(); + inline void cpu_c2(); + inline void cpu_c4(uint16 a, uint16 b); + inline void cpu_c6(uint16 a); + inline void cpu_io(); //opcode functions void init_op_tables(); diff --git a/src/cpu/bcpu/bcpu_mmio.cpp b/src/cpu/bcpu/bcpu_mmio.cpp index c782ff6d..55c175f7 100644 --- a/src/cpu/bcpu/bcpu_mmio.cpp +++ b/src/cpu/bcpu/bcpu_mmio.cpp @@ -303,21 +303,25 @@ void bCPU::mmio_w4206(uint8 value) { //HTIMEL void bCPU::mmio_w4207(uint8 value) { status.hirq_pos = (status.hirq_pos & 0xff00) | value; + if(status.irq_triggered == false)status.irq_pin = 1; } //HTIMEH void bCPU::mmio_w4208(uint8 value) { status.hirq_pos = (status.hirq_pos & 0x00ff) | (value << 8); + if(status.irq_triggered == false)status.irq_pin = 1; } //VTIMEL void bCPU::mmio_w4209(uint8 value) { status.virq_pos = (status.virq_pos & 0xff00) | value; + if(status.irq_triggered == false)status.irq_pin = 1; } //VTIMEH void bCPU::mmio_w420a(uint8 value) { status.virq_pos = (status.virq_pos & 0x00ff) | (value << 8); + if(status.irq_triggered == false)status.irq_pin = 1; } //DMAEN diff --git a/src/ppu/bppu/bppu.cpp b/src/ppu/bppu/bppu.cpp index 3acb40a8..1e61bbf9 100644 --- a/src/ppu/bppu/bppu.cpp +++ b/src/ppu/bppu/bppu.cpp @@ -11,14 +11,18 @@ void bPPU::run() {} void bPPU::scanline() { _y = clock->vcounter(); + _screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256; + _interlace = clock->interlace(); + _interlace_field = clock->interlace_field(); + if(_y > 0 && _y < clock->visible_scanlines()) { - if(clock->interlace() || regs.oam_halve == true) { - output->frame_mode |= PPUOutput::INTERLACE; - output->scanline_mode[_y] |= PPUOutput::INTERLACE; - } if(regs.bg_mode == 5 || regs.bg_mode == 6) { - output->frame_mode |= PPUOutput::DOUBLEWIDTH; - output->scanline_mode[_y] |= PPUOutput::DOUBLEWIDTH; + output->hires = true; + output->line[_y].hires = true; + } + if(_interlace == true) { + output->interlace = true; + output->line[_y].interlace = true; } render_line(); } @@ -26,9 +30,11 @@ void bPPU::scanline() { void bPPU::frame() { snes->notify(SNES::RENDER_FRAME); - output->frame_mode = PPUOutput::NORMAL; + output->hires = false; + output->interlace = false; for(int i=0;i<239;i++) { - output->scanline_mode[i] = PPUOutput::NORMAL; + output->line[i].hires = false; + output->line[i].interlace = false; } } diff --git a/src/ppu/bppu/bppu_mmio.cpp b/src/ppu/bppu/bppu_mmio.cpp index 4122ff31..6b58b0ce 100644 --- a/src/ppu/bppu/bppu_mmio.cpp +++ b/src/ppu/bppu/bppu_mmio.cpp @@ -6,14 +6,14 @@ void bPPU::latch_counters() { uint16 bPPU::get_vram_address() { uint16 addr; - addr = regs.vram_addr << 1; + addr = regs.vram_addr; switch(regs.vram_mapping) { case 0:break; case 1:addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7);break; case 2:addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7);break; case 3:addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7);break; } - return addr; + return (addr << 1); } //INIDISP diff --git a/src/ppu/bppu/bppu_old_render_main.cpp b/src/ppu/bppu/bppu_old_render_main.cpp index 875a77ce..e7ae5c4a 100644 --- a/src/ppu/bppu/bppu_old_render_main.cpp +++ b/src/ppu/bppu/bppu_old_render_main.cpp @@ -195,9 +195,9 @@ uint16 c, cx, cy; uint16 screen_width; uint16 v, vline_pos = clock->vcounter(); v = vline_pos; - screen_width = (output->scanline_mode[v] & PPUOutput::DOUBLEWIDTH)?512:256; + screen_width = (output->line[v].hires)?512:256; - if(!(output->scanline_mode[v] & PPUOutput::INTERLACE)) { + if(output->line[v].interlace == false) { ptr = (uint16*)output->buffer + ((vline_pos << 1)) * 512; } else { ptr = (uint16*)output->buffer + ((vline_pos << 1) + clock->interlace_field()) * 512; diff --git a/src/ppu/bppu/bppu_render.cpp b/src/ppu/bppu/bppu_render.cpp index 0cc9096a..52f25a6c 100644 --- a/src/ppu/bppu/bppu_render.cpp +++ b/src/ppu/bppu/bppu_render.cpp @@ -48,54 +48,55 @@ inline void bPPU::render_line_mode1() { /* Mode 2: -> 1, 2, 3, 4, 5, 6, 7, 8 - OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 + BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 */ inline void bPPU::render_line_mode2() { - render_line_bg(BG1, COLORDEPTH_16, 4, 7); - render_line_bg(BG2, COLORDEPTH_16, 3, 6); - render_line_oam(1, 2, 5, 8); + render_line_bg(BG1, COLORDEPTH_16, 3, 7); + render_line_bg(BG2, COLORDEPTH_16, 1, 5); + render_line_oam(2, 4, 6, 8); } /* Mode 3: -> 1, 2, 3, 4, 5, 6, 7, 8 - OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 + BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 */ inline void bPPU::render_line_mode3() { - render_line_bg(BG1, COLORDEPTH_256, 4, 7); - render_line_bg(BG2, COLORDEPTH_16, 3, 6); + render_line_bg(BG1, COLORDEPTH_256, 3, 7); + render_line_bg(BG2, COLORDEPTH_16, 1, 5); + render_line_oam(2, 4, 6, 8); } /* Mode 4: -> 1, 2, 3, 4, 5, 6, 7, 8 - OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 + BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 */ inline void bPPU::render_line_mode4() { - render_line_bg(BG1, COLORDEPTH_256, 4, 7); - render_line_bg(BG2, COLORDEPTH_4, 3, 6); - render_line_oam(1, 2, 5, 8); + render_line_bg(BG1, COLORDEPTH_256, 3, 7); + render_line_bg(BG2, COLORDEPTH_4, 1, 5); + render_line_oam(2, 4, 6, 8); } /* Mode 5: -> 1, 2, 3, 4, 5, 6, 7, 8 - OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3 + BG2B, OAM0, BG1B, OAM1, BG2A, OAM2, BG1A, OAM3 */ inline void bPPU::render_line_mode5() { - render_line_bg(BG1, COLORDEPTH_16, 4, 7); - render_line_bg(BG2, COLORDEPTH_4, 3, 6); - render_line_oam(1, 2, 5, 8); + render_line_bg(BG1, COLORDEPTH_16, 3, 7); + render_line_bg(BG2, COLORDEPTH_4, 1, 5); + render_line_oam(2, 4, 6, 8); } /* Mode 6: -> 1, 2, 3, 4, 5, 6 - OAM0, OAM1, BG1B, OAM2, BG1A, OAM3 + OAM0, BG1B, OAM1, OAM2, BG1A, OAM3 */ inline void bPPU::render_line_mode6() { - render_line_bg(BG1, COLORDEPTH_16, 3, 5); - render_line_oam(1, 2, 4, 6); + render_line_bg(BG1, COLORDEPTH_16, 2, 5); + render_line_oam(1, 3, 4, 6); } /* @@ -103,27 +104,27 @@ Mode7: -> 1, 2, 3, 4, 5 OAM0, BG1n, OAM1, OAM2, OAM3 +*** +This appears to be incorrect, possibly should be... + BG2B, OAM0, BG1n, OAM1, BG2A, OAM2, OAM3 +*** Mode 7 (extbg): -> 1, 2, 3, 4, 5, 6 BG2B, OAM0, OAM1, BG2A, OAM2, OAM3 */ inline void bPPU::render_line_mode7() { if(regs.mode7_extbg == false) { - render_line_mode7(1, 0, 0); //bg2 priorities are ignored - render_line_oam(0, 2, 3, 4); + render_line_mode7(2, 0, 0); //bg2 priorities are ignored + render_line_oam(1, 3, 4, 5); } else { - render_line_mode7(0, 0, 3); //bg1 priority is ignored - render_line_oam(1, 2, 4, 5); + render_line_mode7(0, 1, 4); //bg1 priority is ignored + render_line_oam(2, 3, 5, 6); } } void bPPU::render_line() { - _screen_width = (regs.bg_mode == 5 || regs.bg_mode == 6)?512:256; - _interlace = clock->interlace(); - _interlace_field = clock->interlace_field(); - if(regs.display_disabled == true) { - memset(output->buffer + (((_y << 1) + _interlace_field) << 9), 0, 1024); + memset(output->buffer + (_y << 10), 0, 2048); return; } diff --git a/src/ppu/bppu/bppu_render_addsub.cpp b/src/ppu/bppu/bppu_render_addsub.cpp index 35367bab..fa727483 100644 --- a/src/ppu/bppu/bppu_render_addsub.cpp +++ b/src/ppu/bppu/bppu_render_addsub.cpp @@ -1,20 +1,7 @@ -namespace bPPUAddSubTables { - uint8 adjust_buffer_full[96] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 - }; - uint8 adjust_buffer_half[96] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 - }; -}; - inline uint16 bPPU::addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg) { int r, g, b; -uint16 cdest = get_palette(cdest_index); -uint16 csrc = get_palette(csrc_index); +uint32 cdest = get_palette(cdest_index); +uint32 csrc = get_palette(csrc_index); uint16 res; //oam palettes 0-3 are not affected by color add/sub if(cdest_bg == OAM) { @@ -22,43 +9,54 @@ uint16 res; return cdest; } } - if(csrc_bg == OAM) { - if(csrc_index < 192) { - return csrc; - } - } switch(regs.color_mode) { case 0: //COLORMODE_ADD: if(regs.color_halve == true) { - r = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest ) & 31) + ((csrc ) & 31) )) >> 1; - g = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 5) & 31) + ((csrc >> 5) & 31) )) >> 1; - b = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 10) & 31) + ((csrc >> 10) & 31) )) >> 1; + cdest = ((cdest << 16) | cdest) & 0x03e07c1f; + csrc = ((csrc << 16) | csrc) & 0x03e07c1f; + cdest += csrc; + cdest >>= 1; + cdest &= 0x03e07c1f; + return (cdest >> 16) | cdest; } else { - r = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest ) & 31) + ((csrc ) & 31) )); - g = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 5) & 31) + ((csrc >> 5) & 31) )); - b = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 10) & 31) + ((csrc >> 10) & 31) )); + cdest = ((cdest << 16) | cdest) & 0x03e07c1f; + csrc = ((csrc << 16) | csrc) & 0x03e07c1f; + cdest += csrc; + if(cdest & 0x04000000)cdest |= 0x03e00000; + if(cdest & 0x00008000)cdest |= 0x00007c00; + if(cdest & 0x00000020)cdest |= 0x0000001f; + cdest &= 0x03e07c1f; + return (cdest >> 16) | cdest; } break; case 1: //COLORMODE_SUB: if(regs.color_halve == true) { - r = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest ) & 31) - ((csrc ) & 31) )) >> 1; - g = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 5) & 31) - ((csrc >> 5) & 31) )) >> 1; - b = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 10) & 31) - ((csrc >> 10) & 31) )) >> 1; + if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00; + else cdest -= (csrc & 0x7c00); + if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0; + else cdest -= (csrc & 0x03e0); + if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f; + else cdest -= (csrc & 0x001f); + return (cdest & 0x7bde) >> 1; } else { - r = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest ) & 31) - ((csrc ) & 31) )); - g = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 5) & 31) - ((csrc >> 5) & 31) )); - b = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 10) & 31) - ((csrc >> 10) & 31) )); + if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00; + else cdest -= (csrc & 0x7c00); + if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0; + else cdest -= (csrc & 0x03e0); + if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f; + else cdest -= (csrc & 0x001f); + return cdest; } break; } - return ((r) | (g << 5) | (b << 10)); + return 0x0000; //prevent annoying warning message } inline uint16 bPPU::addsub_pixel(int cdest_index, int cdest_bg) { int r, g, b; -uint16 cdest = get_palette(cdest_index); -uint16 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10); +uint32 cdest = get_palette(cdest_index); +uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10); uint16 res; //only oam palettes 4-7 are affected by color add/sub if(cdest_bg == OAM) { @@ -70,26 +68,42 @@ uint16 res; switch(regs.color_mode) { case 0: //COLORMODE_ADD: if(regs.color_halve == true && regs.addsub_mode == 0) { - r = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest ) & 31) + ((csrc ) & 31) )) >> 1; - g = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 5) & 31) + ((csrc >> 5) & 31) )) >> 1; - b = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 10) & 31) + ((csrc >> 10) & 31) )) >> 1; + cdest = ((cdest << 16) | cdest) & 0x03e07c1f; + csrc = ((csrc << 16) | csrc) & 0x03e07c1f; + cdest += csrc; + cdest >>= 1; + cdest &= 0x03e07c1f; + return (cdest >> 16) | cdest; } else { - r = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest ) & 31) + ((csrc ) & 31) )); - g = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 5) & 31) + ((csrc >> 5) & 31) )); - b = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 10) & 31) + ((csrc >> 10) & 31) )); + cdest = ((cdest << 16) | cdest) & 0x03e07c1f; + csrc = ((csrc << 16) | csrc) & 0x03e07c1f; + cdest += csrc; + if(cdest & 0x04000000)cdest |= 0x03e00000; + if(cdest & 0x00008000)cdest |= 0x00007c00; + if(cdest & 0x00000020)cdest |= 0x0000001f; + cdest &= 0x03e07c1f; + return (cdest >> 16) | cdest; } break; case 1: //COLORMODE_SUB: if(regs.color_halve == true && regs.addsub_mode == 0) { - r = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest ) & 31) - ((csrc ) & 31) )) >> 1; - g = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 5) & 31) - ((csrc >> 5) & 31) )) >> 1; - b = *(bPPUAddSubTables::adjust_buffer_half + 32 + ( ((cdest >> 10) & 31) - ((csrc >> 10) & 31) )) >> 1; + if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00; + else cdest -= (csrc & 0x7c00); + if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0; + else cdest -= (csrc & 0x03e0); + if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f; + else cdest -= (csrc & 0x001f); + return (cdest & 0x7bde) >> 1; } else { - r = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest ) & 31) - ((csrc ) & 31) )); - g = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 5) & 31) - ((csrc >> 5) & 31) )); - b = *(bPPUAddSubTables::adjust_buffer_full + 32 + ( ((cdest >> 10) & 31) - ((csrc >> 10) & 31) )); + if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00; + else cdest -= (csrc & 0x7c00); + if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0; + else cdest -= (csrc & 0x03e0); + if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f; + else cdest -= (csrc & 0x001f); + return cdest; } break; } - return ((r) | (g << 5) | (b << 10)); + return 0x0000; //prevent annoying warning message } diff --git a/src/ppu/bppu/bppu_render_bg.cpp b/src/ppu/bppu/bppu_render_bg.cpp index b01e299f..a131b09c 100644 --- a/src/ppu/bppu/bppu_render_bg.cpp +++ b/src/ppu/bppu/bppu_render_bg.cpp @@ -111,8 +111,6 @@ uint8 *wt_main = main_windowtable[bg]; uint8 *wt_sub = sub_windowtable[bg]; build_window_tables(bg); for(screen_x=0;screen_x<_screen_width;screen_x++) { - if(wt_main[screen_x] && wt_sub[screen_x])continue; - if(regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6) { if(regs.bg_mode == 6) { tile_x = (mtable[screen_x + (hscroll & 15)] >> 4); diff --git a/src/ppu/bppu/bppu_render_line.cpp b/src/ppu/bppu/bppu_render_line.cpp index 5df8e34c..67e087ad 100644 --- a/src/ppu/bppu/bppu_render_line.cpp +++ b/src/ppu/bppu/bppu_render_line.cpp @@ -53,7 +53,10 @@ inline void bPPU::render_line_output() { int x; uint16 _r; uint16 *ptr; - ptr = (uint16*)output->buffer + (((_y << 1) + _interlace_field) << 9); //((y * 2) + interlace) * scanline_width + ptr = (uint16*)output->buffer + (_y << 10); + if(_interlace == true) { + ptr += _interlace_field << 9; + } uint16 *ltable; ltable = (uint16*)light_table + (regs.display_brightness << 16); diff --git a/src/ppu/bppu/bppu_render_oam.cpp b/src/ppu/bppu/bppu_render_oam.cpp index ba5de57c..b487604b 100644 --- a/src/ppu/bppu/bppu_render_oam.cpp +++ b/src/ppu/bppu/bppu_render_oam.cpp @@ -81,11 +81,13 @@ int tile_width; } else { y = (_y - current_sprite.y); } - y &= 255; if(regs.oam_halve == true) { y <<= 1; - y += _interlace_field; + if(_interlace == true && _screen_width == 512) { + y += _interlace_field; + } } + y &= 255; chr = current_sprite.character; tiledata_inc = (chr & 0x100)?(regs.oam_nameselect << 13):0; diff --git a/src/ppu/ppu.cpp b/src/ppu/ppu.cpp index 9b0466a4..8f9ff5b5 100644 --- a/src/ppu/ppu.cpp +++ b/src/ppu/ppu.cpp @@ -3,9 +3,11 @@ PPUOutput::PPUOutput() { buffer = (uint16*)memalloc(512 * 478 * 2, "PPUOutput::buffer"); memset(buffer, 0, 512 * 478 * 2); - frame_mode = NORMAL; + hires = false; + interlace = false; for(int i=0;i<239;i++) { - scanline_mode[i] = NORMAL; + line[i].hires = false; + line[i].interlace = false; } } diff --git a/src/ppu/ppu.h b/src/ppu/ppu.h index 1e16b35b..4aeefdff 100644 --- a/src/ppu/ppu.h +++ b/src/ppu/ppu.h @@ -1,12 +1,9 @@ class PPUOutput { public: -enum { - NORMAL = 0, - INTERLACE = 1, - DOUBLEWIDTH = 2 -}; -uint8 frame_mode; -uint8 scanline_mode[239]; +bool hires, interlace; +struct { +bool hires, interlace; +}line[239]; uint16 *buffer; PPUOutput(); ~PPUOutput(); diff --git a/src/reader/reader.h b/src/reader/reader.h index 38fea7dd..200fe92f 100644 --- a/src/reader/reader.h +++ b/src/reader/reader.h @@ -25,7 +25,7 @@ enum { class Writer { public: - virtual void write(uint8 *buffer, uint32 length); + virtual void write(uint8 *buffer, uint32 length) = 0; }; class FileWriter : public Writer { diff --git a/src/win/Makefile b/src/win/Makefile index 2abf98c7..40414f21 100644 --- a/src/win/Makefile +++ b/src/win/Makefile @@ -8,7 +8,7 @@ OBJS = winmain.obj \ cpu.obj bcpu.obj \ ppu.obj bppu.obj \ snes.obj -LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib +LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dxguid.lib all: $(OBJS) $(CC) /Febsnes_g2.exe $(CFLAGS) $(OBJS) $(LIBS) diff --git a/src/win/config.cpp b/src/win/config.cpp index ba910014..79a0f1c5 100644 --- a/src/win/config.cpp +++ b/src/win/config.cpp @@ -6,6 +6,8 @@ public: struct { uint32 mode; uint32 use_vram; + uint32 color_curve; + uint32 vblank; }video; struct { @@ -13,8 +15,10 @@ struct { }gui; Config() { - __config_add(video.mode, 1, DEC); - __config_add(video.use_vram, true, TRUEFALSE); - __config_add(gui.show_fps, true, TRUEFALSE); + __config_add(video.mode, 1, DEC); + __config_add(video.use_vram, true, TRUEFALSE); + __config_add(video.color_curve, true, ENABLED); + __config_add(video.vblank, false, TRUEFALSE); + __config_add(gui.show_fps, true, TRUEFALSE); } }cfg; diff --git a/src/win/dd_renderer.cpp b/src/win/dd_renderer.cpp index f753cc85..6d3d2618 100644 --- a/src/win/dd_renderer.cpp +++ b/src/win/dd_renderer.cpp @@ -1,8 +1,20 @@ DDRenderer::DDRenderer() { lpdd = 0; + lpdd7 = 0; lpdds = 0; lpddsb = 0; lpddc = 0; + +int i, c; + for(i=0,c=0;i<16;i++) { + color_curve_table[i] = c; + c = c + i + 1; + } + for(;i<31;i++) { + color_curve_table[i] = c; + c += 8; + } + color_curve_table[i] = 0xff; } void DDRenderer::update_color_lookup_table() { @@ -14,6 +26,11 @@ int i, r, g, b; r = (i ) & 31; g = (i >> 5) & 31; b = (i >> 10) & 31; + if(cfg.video.color_curve) { + r = color_curve_table[r] >> 3; + g = color_curve_table[g] >> 3; + b = color_curve_table[b] >> 3; + } color_lookup_table[i] = (r << 10) | (g << 5) | (b); } } else if(color_depth == 16) { @@ -21,7 +38,13 @@ int i, r, g, b; r = (i ) & 31; g = (i >> 5) & 31; b = (i >> 10) & 31; - g = (g << 1) | (g >> 4); + if(cfg.video.color_curve) { + r = color_curve_table[r] >> 3; + g = color_curve_table[g] >> 2; + b = color_curve_table[b] >> 3; + } else { + g = (g << 1) | (g >> 4); + } color_lookup_table[i] = (r << 11) | (g << 5) | (b); } } else if(color_depth == 32) { @@ -29,9 +52,15 @@ int i, r, g, b; r = (i ) & 31; g = (i >> 5) & 31; b = (i >> 10) & 31; - r = (r << 3) | (r >> 2); - g = (g << 3) | (g >> 2); - b = (b << 3) | (b >> 2); + if(cfg.video.color_curve) { + r = color_curve_table[r]; + g = color_curve_table[g]; + b = color_curve_table[b]; + } else { + r = (r << 3) | (r >> 2); + g = (g << 3) | (g >> 2); + b = (b << 3) | (b >> 2); + } color_lookup_table[i] = (r << 16) | (g << 8) | (b); } } else { @@ -46,6 +75,17 @@ void DDRenderer::set_window(HWND hwnd_handle) { hwnd = hwnd_handle; } even in 24/32-bit mode. This is possible because DDraw automatically handles conversion from 16bpp->32bpp in hardware. This only works when both the source and dest buffers are in VRAM, though. + + The SNES resolution is 256x224. The top scanline is never drawn, so + 256x223 is used. Hires mode doubles the screen width, and hires+interlace + double the screen height, making the resolution 512x446. + There is one more problem, however. On some video cards, when blitting + from video memory from 256x223->512x446, a bilinear filter is applied by + the video card, and sometimes this filter tries to read past the source + video memory to get interpolation data. This results in a line of garble + on the right and bottom edges of the screen. Therefore, an additional + 4 pixels in each direction is added to the backbuffer. + The backbuffer is thusly 512+4 * 476+4 */ void DDRenderer::create_backbuffer() { int color_depth; @@ -69,8 +109,8 @@ int color_depth; ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; } - ddsd.dwWidth = 512; - ddsd.dwHeight = 478; + ddsd.dwWidth = 512 + 4; + ddsd.dwHeight = 476 + 4; ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; @@ -79,7 +119,7 @@ int color_depth; ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0; ddsd.ddpfPixelFormat.dwBBitMask = 0x001f; - if(lpdd->CreateSurface(&ddsd, &lpddsb, 0) == DD_OK)return; + if(lpdd->CreateSurface(&ddsd, &lpddsb, 0) == DD_OK)goto clear_backbuffer; try_native_backbuffer: memset(&ddsd, 0, sizeof(DDSURFACEDESC)); @@ -92,14 +132,26 @@ try_native_backbuffer: ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; } - ddsd.dwWidth = 512; - ddsd.dwHeight = 478; + ddsd.dwWidth = 512 + 4; + ddsd.dwHeight = 476 + 4; lpdd->CreateSurface(&ddsd, &lpddsb, 0); + +clear_backbuffer: + if(!lpddsb) { + alert("Error: Failed to create DirectDraw backbuffer, cannot continue"); + exit(0); + } + +DDBLTFX fx; + fx.dwSize = sizeof(DDBLTFX); + fx.dwFillColor = 0x00000000; + lpddsb->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); } void DDRenderer::to_windowed() { destroy(); + fullscreen = false; DirectDrawCreate(0, &lpdd, 0); lpdd->SetCooperativeLevel(hwnd, DDSCL_NORMAL); @@ -115,14 +167,22 @@ void DDRenderer::to_windowed() { create_backbuffer(); update_color_lookup_table(); - update(); + redraw(); } -void DDRenderer::to_fullscreen() { +void DDRenderer::to_fullscreen(int _width, int _height) { destroy(); + fullscreen = true; + width = _width; + height = _height; DirectDrawCreate(0, &lpdd, 0); +/* + lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7); + lpdd7->SetCooperativeLevel(hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); + lpdd7->SetDisplayMode(width, height, 16, 60, 0); +*/ lpdd->SetCooperativeLevel(hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); - lpdd->SetDisplayMode(640, 480, 16); + lpdd->SetDisplayMode(width, height, 16); memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); @@ -136,28 +196,40 @@ void DDRenderer::to_fullscreen() { create_backbuffer(); update_color_lookup_table(); - update(); + redraw(); } -void DDRenderer::set_source_window(RECT *rs) { - switch(ppu->output->frame_mode) { - case 0:SetRect(rs, 0, 0, 256, 223);break; - case 1:SetRect(rs, 0, 0, 256, 446);break; - case 2:SetRect(rs, 0, 0, 512, 223);break; - case 3:SetRect(rs, 0, 0, 512, 446);break; - } +void DDRenderer::set_source_window() { + SetRect(&lpddrc, 0, 0, + (ppu->output->hires == false)?256:512, + (ppu->output->interlace == false)?223:446); } void DDRenderer::redraw() { -RECT rd, rs; +RECT rd; POINT p; HRESULT hr; - p.x = p.y = 0; - ClientToScreen(hwnd, &p); - GetClientRect(hwnd, &rd); - OffsetRect(&rd, p.x, p.y); - set_source_window(&rs); - hr = lpdds->Blt(&rd, lpddsb, &rs, DDBLT_WAIT, 0); +int rx, ry; + if(fullscreen == false) { + p.x = p.y = 0; + ClientToScreen(hwnd, &p); + GetClientRect(hwnd, &rd); + OffsetRect(&rd, p.x, p.y); + } else { + switch(width) { + case 640: //x480 + SetRect(&rd, 0, 2, 512, 448); + OffsetRect(&rd, (640 - 512) / 2, (480 - 446) / 2); + break; + case 1024: //x768 + SetRect(&rd, 0, 0, 1024, 768); + break; + } + } + if(cfg.video.vblank) { + lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0); + } + hr = lpdds->Blt(&rd, lpddsb, &lpddrc, DDBLT_WAIT, 0); if(hr == DDERR_SURFACELOST) { lpdds->Restore(); lpddsb->Restore(); @@ -168,7 +240,7 @@ uint32 fps; char s[256], t[256]; fps_timer->tick(); if(fps_timer->second_passed() == true) { - sprintf(s, "bsnes v" BSNES_VERSION " ~byuu"); + sprintf(s, BSNES_TITLE); if(rom_image->loaded() == true) { fps = fps_timer->get_ticks(); if(w_main->frameskip == 0) { @@ -183,147 +255,51 @@ char s[256], t[256]; } } +#include "dd_renderer16.cpp" void DDRenderer::update16() { HRESULT hr; hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); if(hr != DD_OK)return; -uint16 *src = (uint16*)ppu->output->buffer; -uint16 *dest = (uint16*)ddsd.lpSurface; -uint32 pitch; -int x, y; -/* skip first scanline */ - src += 1024; - - if(clock->overscan() == true) { - if(ppu->output->frame_mode & PPUOutput::INTERLACE) { - src += 1024 * 16; + set_source_window(); + if(ppu->output->hires == false) { + if(ppu->output->interlace == false) { + update16_256x224(); } else { - src += 1024 * 8; - } - } - - if(ppu->output->frame_mode == PPUOutput::NORMAL) { - /* 256x223 */ - pitch = (ddsd.lPitch >> 1) - 256; - y = 223; - while(y--) { - x = 256; - while(x--) { - *dest++ = color_lookup_table[*src]; - src += 2; - } - dest += pitch; - src += 512; - } - } else if(ppu->output->frame_mode == PPUOutput::INTERLACE) { - /* 256x446 */ - pitch = (ddsd.lPitch >> 1) - 256; - y = 446; - while(y--) { - x = 256; - while(x--) { - *dest++ = color_lookup_table[*src]; - src += 2; - } - dest += pitch; - } - } else if(ppu->output->frame_mode == PPUOutput::DOUBLEWIDTH) { - /* 512x223 */ - pitch = (ddsd.lPitch >> 1) - 512; - y = 223; - while(y--) { - x = 512; - while(x--) { - *dest++ = color_lookup_table[*src++]; - } - dest += pitch; - src += 512; + update16_256x448(); } } else { - /* 512x446 */ - pitch = (ddsd.lPitch >> 1) - 512; - y = 446; - while(y--) { - x = 512; - while(x--) { - *dest++ = color_lookup_table[*src++]; - } - dest += pitch; + if(ppu->output->interlace == false) { + update16_512x224(); + } else { + update16_512x448(); } } + lpddsb->Unlock(0); } +#include "dd_renderer32.cpp" void DDRenderer::update32() { HRESULT hr; hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); if(hr != DD_OK)return; -uint16 *src = (uint16*)ppu->output->buffer; -uint32 *dest = (uint32*)ddsd.lpSurface; -uint32 pitch; -int x, y; -/* skip first scanline */ - src += 1024; - - if(clock->overscan() == true) { - if(ppu->output->frame_mode & PPUOutput::INTERLACE) { - src += 1024 * 16; + set_source_window(); + if(ppu->output->hires == false) { + if(ppu->output->interlace == false) { + update32_256x224(); } else { - src += 1024 * 8; - } - } - - if(ppu->output->frame_mode == PPUOutput::NORMAL) { - /* 256x223 */ - pitch = (ddsd.lPitch >> 2) - 256; - y = 223; - while(y--) { - x = 256; - while(x--) { - *dest++ = color_lookup_table[*src]; - src += 2; - } - dest += pitch; - src += 512; - } - } else if(ppu->output->frame_mode == PPUOutput::INTERLACE) { - /* 256x446 */ - pitch = (ddsd.lPitch >> 2) - 256; - y = 446; - while(y--) { - x = 256; - while(x--) { - *dest++ = color_lookup_table[*src]; - src += 2; - } - dest += pitch; - } - } else if(ppu->output->frame_mode == PPUOutput::DOUBLEWIDTH) { - /* 512x223 */ - pitch = (ddsd.lPitch >> 2) - 512; - y = 223; - while(y--) { - x = 512; - while(x--) { - *dest++ = color_lookup_table[*src++]; - } - dest += pitch; - src += 512; + update32_256x448(); } } else { - /* 512x446 */ - pitch = (ddsd.lPitch >> 2) - 512; - y = 446; - while(y--) { - x = 512; - while(x--) { - *dest++ = color_lookup_table[*src++]; - } - dest += pitch; + if(ppu->output->interlace == false) { + update32_512x224(); + } else { + update32_512x448(); } } + lpddsb->Unlock(0); } @@ -353,6 +329,10 @@ void DDRenderer::destroy() { lpdds->Release(); lpdds = 0; } + if(lpdd7) { + lpdd7->Release(); + lpdd7 = 0; + } if(lpdd) { lpdd->Release(); lpdd = 0; diff --git a/src/win/dd_renderer.h b/src/win/dd_renderer.h index acaf8bfe..f1054b1d 100644 --- a/src/win/dd_renderer.h +++ b/src/win/dd_renderer.h @@ -2,20 +2,33 @@ class DDRenderer { public: LPDIRECTDRAW lpdd; +LPDIRECTDRAW7 lpdd7; LPDIRECTDRAWSURFACE lpdds, lpddsb; LPDIRECTDRAWCLIPPER lpddc; DDSURFACEDESC ddsd; DDSCAPS ddscaps; +RECT lpddrc; HWND hwnd; -uint8 color_depth; +bool fullscreen; +int width, height; //used for fullscreen mode clipping only +uint8 color_depth; +uint8 color_curve_table[32]; uint32 color_lookup_table[65536]; void set_window(HWND hwnd_handle); void create_backbuffer(); void to_windowed(); - void to_fullscreen(); - void set_source_window(RECT *rs); + void to_fullscreen(int _width, int _height); + void set_source_window(); void redraw(); + inline void update16_256x224(); + inline void update16_256x448(); + inline void update16_512x224(); + inline void update16_512x448(); void update16(); + inline void update32_256x224(); + inline void update32_256x448(); + inline void update32_512x224(); + inline void update32_512x448(); void update32(); void update(); void destroy(); diff --git a/src/win/dd_renderer16.cpp b/src/win/dd_renderer16.cpp new file mode 100644 index 00000000..00fa4b2b --- /dev/null +++ b/src/win/dd_renderer16.cpp @@ -0,0 +1,123 @@ +inline void DDRenderer::update16_256x224() { +uint16 *src; +uint16 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint16*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 1) - 256; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 8; + } + + for(y=1+overscan_adjust;y<224+overscan_adjust;y++) { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + src += 2; + } + dest += pitch; + src += 512; + } +} + +inline void DDRenderer::update16_256x448() { +uint16 *src; +uint16 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint16*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 1) - 256; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 16; + } + + for(y=2+overscan_adjust;y<448+overscan_adjust;y++) { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + src += 2; + } + dest += pitch; + if(ppu->output->line[y >> 1].interlace == false) { + src += (y & 1)?512:-512; + } + } +} + +inline void DDRenderer::update16_512x224() { +uint16 *src; +uint16 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint16*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 1) - 512; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 8; + } + + for(y=1+overscan_adjust;y<224+overscan_adjust;y++) { + if(ppu->output->line[y].hires == true) { + x = 512; + while(x--) { + *dest++ = color_lookup_table[*src++]; + } + } else { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + *dest++ = color_lookup_table[*src]; + src += 2; + } + } + dest += pitch; + src += 512; + } +} + +inline void DDRenderer::update16_512x448() { +uint16 *src; +uint16 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint16*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 1) - 512; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 16; + } + + for(y=2+overscan_adjust;y<448+overscan_adjust;y++) { + if(ppu->output->line[y >> 1].hires == true) { + x = 512; + while(x--) { + *dest++ = color_lookup_table[*src++]; + } + } else { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + *dest++ = color_lookup_table[*src]; + src += 2; + } + } + dest += pitch; + if(ppu->output->line[y >> 1].interlace == false) { + src += (y & 1)?512:-512; + } + } +} diff --git a/src/win/dd_renderer32.cpp b/src/win/dd_renderer32.cpp new file mode 100644 index 00000000..9a097583 --- /dev/null +++ b/src/win/dd_renderer32.cpp @@ -0,0 +1,123 @@ +inline void DDRenderer::update32_256x224() { +uint16 *src; +uint32 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint32*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 2) - 256; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 8; + } + + for(y=1+overscan_adjust;y<224+overscan_adjust;y++) { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + src += 2; + } + dest += pitch; + src += 512; + } +} + +inline void DDRenderer::update32_256x448() { +uint16 *src; +uint32 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint32*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 2) - 256; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 16; + } + + for(y=2+overscan_adjust;y<448+overscan_adjust;y++) { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + src += 2; + } + dest += pitch; + if(ppu->output->line[y >> 1].interlace == false) { + src += (y & 1)?512:-512; + } + } +} + +inline void DDRenderer::update32_512x224() { +uint16 *src; +uint32 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint32*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 2) - 512; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 8; + } + + for(y=1+overscan_adjust;y<224+overscan_adjust;y++) { + if(ppu->output->line[y].hires == true) { + x = 512; + while(x--) { + *dest++ = color_lookup_table[*src++]; + } + } else { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + *dest++ = color_lookup_table[*src]; + src += 2; + } + } + dest += pitch; + src += 512; + } +} + +inline void DDRenderer::update32_512x448() { +uint16 *src; +uint32 *dest; +uint32 pitch; +int x, y; + src = (uint16*)ppu->output->buffer + (1 << 10); + dest = (uint32*)ddsd.lpSurface; + pitch = (ddsd.lPitch >> 2) - 512; + +int overscan_adjust = 0; + if(clock->overscan() == true) { + src += 8 << 10; + overscan_adjust = 16; + } + + for(y=2+overscan_adjust;y<448+overscan_adjust;y++) { + if(ppu->output->line[y >> 1].hires == true) { + x = 512; + while(x--) { + *dest++ = color_lookup_table[*src++]; + } + } else { + x = 256; + while(x--) { + *dest++ = color_lookup_table[*src]; + *dest++ = color_lookup_table[*src]; + src += 2; + } + } + dest += pitch; + if(ppu->output->line[y >> 1].interlace == false) { + src += (y & 1)?512:-512; + } + } +} diff --git a/src/win/ui.cpp b/src/win/ui.cpp index 91f4e315..b1fa2ff6 100644 --- a/src/win/ui.cpp +++ b/src/win/ui.cpp @@ -42,5 +42,10 @@ void init_ui1() { SetFocus(w_main->hwnd); dd_renderer->set_window(w_main->hwnd); dd_renderer->to_windowed(); + + w_main->show_menu(); + w_main->set_video_mode(cfg.video.mode); + w_main->set_frameskip(0); + bsnes->debugger_deactivate(); } diff --git a/src/win/ui.h b/src/win/ui.h index f8def5da..41d27037 100644 --- a/src/win/ui.h +++ b/src/win/ui.h @@ -1,7 +1,9 @@ enum { VIDEOMODE_256x224w = 0, VIDEOMODE_512x448w, - VIDEOMODE_960x720w + VIDEOMODE_960x720w, + VIDEOMODE_640x480f, + VIDEOMODE_1024x768f }; enum { @@ -23,6 +25,12 @@ enum { MENU_SETTINGS_VIDEOMODE_256x224w, MENU_SETTINGS_VIDEOMODE_512x448w, MENU_SETTINGS_VIDEOMODE_960x720w, + MENU_SETTINGS_VIDEOMODE_640x480f, + MENU_SETTINGS_VIDEOMODE_1024x768f, + MENU_SETTINGS_USEVRAM, + MENU_SETTINGS_VBLANK, + MENU_SETTINGS_COLORCURVE, + MENU_SETTINGS_SHOWFPS, MENU_SETTINGS_DEBUGGER }; @@ -122,27 +130,36 @@ enum { class Window { public: -HWND hwnd; +HWND hwnd; HMENU hmenu; -bool visible, menu_visible; +bool fullscreen, visible, cursor_visible; +RECT workarea, wa_offset; +struct { int width, height; }window; void resize(int width, int height); + void center(); + void show_menu(); + void hide_menu(); + void show(); + void hide(); + void to_left(HWND _hwnd = 0); void to_center(); void to_right(); void to_top(); void to_middle(); void to_bottom(HWND _hwnd = 0); - void hide(); - void show(); - void show_menu(); - void hide_menu(); + Window(); }; class MainWindow : public Window { public: uint8 frameskip; +int width, height; + void to_fullscreen(); + void to_windowed(); void set_frameskip(uint8 fs); + void adjust_video_mode(bool fullscreen_mode); void set_video_mode(uint8 mode); void menu_load(); void menu_unload(); diff --git a/src/win/ui_main.cpp b/src/win/ui_main.cpp index b105956c..dfd8b6a1 100644 --- a/src/win/ui_main.cpp +++ b/src/win/ui_main.cpp @@ -15,32 +15,86 @@ void MainWindow::set_frameskip(uint8 fs) { w_main->frameskip = fs; } -void MainWindow::set_video_mode(uint8 mode) { - hide(); - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_256x224w, MF_UNCHECKED); - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_512x448w, MF_UNCHECKED); - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_960x720w, MF_UNCHECKED); - switch(mode) { - case VIDEOMODE_256x224w: - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_256x224w, MF_CHECKED); - resize(256, 223); - break; - case VIDEOMODE_512x448w: - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_512x448w, MF_CHECKED); - resize(512, 446); - break; - case VIDEOMODE_960x720w: - CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VIDEOMODE_960x720w, MF_CHECKED); - resize(960, 720); - break; +void MainWindow::to_fullscreen() { + if(bsnes->debugger_enabled() == true) { + bsnes->debugger_disable(); } + SetWindowLong(hwnd, GWL_STYLE, WS_POPUP); + SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOPMOST); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, width, height, 0); + dd_renderer->to_fullscreen(width, height); + hide_menu(); +} + +void MainWindow::to_windowed() { + SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); + SetWindowLong(hwnd, GWL_EXSTYLE, 0); +//always call in case the video mode change is simply changing +//the backbuffer from a VRAM surface to a DRAM surface. + dd_renderer->to_windowed(); + if(dd_renderer->fullscreen == true) { + show_menu(); + } +} + +void MainWindow::adjust_video_mode(bool fullscreen_mode) { + fullscreen = fullscreen_mode; + + if(fullscreen == true) { + to_fullscreen(); + } else { + to_windowed(); + } + + resize(width, height); + if(fullscreen == false)center(); + if(bsnes->debugger_enabled() == true) { to_bottom(); to_right(); - } else { - to_middle(); - to_center(); } +} + +void MainWindow::set_video_mode(uint8 mode) { + hide(); + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_256x224w, MF_UNCHECKED); + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_512x448w, MF_UNCHECKED); + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_960x720w, MF_UNCHECKED); + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_640x480f, MF_UNCHECKED); + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_1024x768f, MF_UNCHECKED); + switch(mode) { + case VIDEOMODE_256x224w: + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_256x224w, MF_CHECKED); + width = 256; + height = 223; + adjust_video_mode(false); + break; + case VIDEOMODE_512x448w: + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_512x448w, MF_CHECKED); + width = 512; + height = 446; + adjust_video_mode(false); + break; + case VIDEOMODE_960x720w: + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_960x720w, MF_CHECKED); + width = 960; + height = 720; + adjust_video_mode(false); + break; + case VIDEOMODE_640x480f: + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_640x480f, MF_CHECKED); + width = 640; + height = 480; + adjust_video_mode(true); + break; + case VIDEOMODE_1024x768f: + CheckMenuItem(hmenu, MENU_SETTINGS_VIDEOMODE_1024x768f, MF_CHECKED); + width = 1024; + height = 768; + adjust_video_mode(true); + break; + } + cfg.video.mode = mode; show(); } @@ -79,6 +133,16 @@ void MainWindow::menu_unload() { long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch(msg) { + case WM_KEYDOWN: + if(wparam == VK_ESCAPE) { + if(GetMenu(w_main->hwnd) == NULL) { + w_main->show_menu(); + } else { + w_main->hide_menu(); + } + w_main->center(); + } + break; case WM_COMMAND: switch(LOWORD(wparam)) { case MENU_FILE_LOAD: @@ -123,6 +187,31 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { case MENU_SETTINGS_VIDEOMODE_960x720w: w_main->set_video_mode(VIDEOMODE_960x720w); break; + case MENU_SETTINGS_VIDEOMODE_640x480f: + w_main->set_video_mode(VIDEOMODE_640x480f); + break; + case MENU_SETTINGS_VIDEOMODE_1024x768f: + w_main->set_video_mode(VIDEOMODE_1024x768f); + break; + case MENU_SETTINGS_USEVRAM: + cfg.video.use_vram ^= 1; + w_main->set_video_mode(cfg.video.mode); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_USEVRAM, (cfg.video.use_vram)?MF_CHECKED:MF_UNCHECKED); + break; + case MENU_SETTINGS_VBLANK: + cfg.video.vblank ^= 1; + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VBLANK, (cfg.video.vblank)?MF_CHECKED:MF_UNCHECKED); + break; + case MENU_SETTINGS_COLORCURVE: + cfg.video.color_curve ^= 1; + dd_renderer->update_color_lookup_table(); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_COLORCURVE, (cfg.video.color_curve)?MF_CHECKED:MF_UNCHECKED); + break; + case MENU_SETTINGS_SHOWFPS: + cfg.gui.show_fps ^= 1; + SetWindowText(w_main->hwnd, BSNES_TITLE); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_SHOWFPS, (cfg.gui.show_fps)?MF_CHECKED:MF_UNCHECKED); + break; case MENU_SETTINGS_DEBUGGER: if(bsnes->debugger_enabled() == true) { bsnes->debugger_disable(); @@ -157,7 +246,7 @@ WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; RegisterClass(&wc); - w_main->hwnd = CreateWindow("bsnes", "bsnes v" BSNES_VERSION " ~byuu", + w_main->hwnd = CreateWindowEx(0, "bsnes", "bsnes v" BSNES_VERSION " ~byuu", WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 0, 0, 512, 446, 0, 0, GetModuleHandle(0), 0); @@ -192,18 +281,26 @@ HMENU hsubmenu, hbranchmenu; AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Frameskip"); hbranchmenu = CreatePopupMenu(); - AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_256x224w, "256x224 Windowed [16:15]"); - AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_512x448w, "512x448 Windowed [16:15]"); - AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_960x720w, "960x720 Windowed [4:3]"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_256x224w, "256x224 Windowed [16:15]"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_512x448w, "512x448 Windowed [16:15]"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_960x720w, "960x720 Windowed [4:3]"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_640x480f, "640x480 Fullscreen [16:15]"); + AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_VIDEOMODE_1024x768f, "1024x768 Fullscreen [4:3]"); AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Video Mode"); + AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_USEVRAM, "Use &Video Memory Surface"); + AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_VBLANK, "&Wait for Vertical Retrace"); + AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_COLORCURVE, "Use &Color Curve"); + AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_SHOWFPS, "&Show FPS"); + AppendMenu(hsubmenu, MF_SEPARATOR, 0, ""); AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_DEBUGGER, "&Debugger"); AppendMenu(w_main->hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings"); - w_main->show_menu(); - w_main->set_video_mode(cfg.video.mode); - w_main->set_frameskip(0); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_USEVRAM, (cfg.video.use_vram)?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_VBLANK, (cfg.video.vblank)?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_COLORCURVE, (cfg.video.color_curve)?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(w_main->hmenu, MENU_SETTINGS_SHOWFPS, (cfg.gui.show_fps)?MF_CHECKED:MF_UNCHECKED); } MainWindow::MainWindow() { diff --git a/src/win/ui_window.cpp b/src/win/ui_window.cpp index 0b0b07dc..1696d73c 100644 --- a/src/win/ui_window.cpp +++ b/src/win/ui_window.cpp @@ -1,14 +1,95 @@ void Window::resize(int width, int height) { +int style; + window.width = width; + window.height = height; + + style = GetWindowLong(hwnd, GWL_STYLE); + if(style & WS_CAPTION) { + width += GetSystemMetrics(SM_CXFIXEDFRAME) << 1; + height += GetSystemMetrics(SM_CYFIXEDFRAME) << 1; + height += GetSystemMetrics(SM_CYCAPTION); + } + + if(width == GetSystemMetrics(SM_CXSCREEN) && height == GetSystemMetrics(SM_CYSCREEN)) { + fullscreen = true; + } else { + fullscreen = false; + } + + if(fullscreen == false) { + if(GetMenu(hwnd) != 0) { + height += GetSystemMetrics(SM_CYMENU); + } + SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE); + } else { + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, width, height, 0); + } +} + +void Window::center() { RECT rc; -int x, y, wx, wy; - hide(); - SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER); - GetClientRect(hwnd, &rc); - x = width + width - (rc.right - rc.left); - y = height + height - (rc.bottom - rc.top); - wx = (GetSystemMetrics(SM_CXSCREEN) - x) / 2; - wy = (GetSystemMetrics(SM_CYSCREEN) - y) / 2; - SetWindowPos(hwnd, 0, wx, wy, x, y, SWP_NOZORDER); +POINT p; + if(fullscreen == true) { + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, window.width, window.height, 0); + return; + } + GetWindowRect(hwnd, &rc); + p.x = p.y = 0; + ClientToScreen(hwnd, &p); + OffsetRect(&rc, p.x, p.y); +int sw = GetSystemMetrics(SM_CXSCREEN), + sh = GetSystemMetrics(SM_CYSCREEN); +int x = (sw - (rc.right - rc.left)) >> 1, + y = (sh - (rc.bottom - rc.top)) >> 1; + SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); +} + +void Window::show_menu() { +RECT rc; +int width, height; + if(GetMenu(hwnd) != NULL)return; + + SetMenu(hwnd, hmenu); + if(cursor_visible == false) { + ShowCursor(TRUE); + cursor_visible = true; + } + if(fullscreen == true) { + return; + } + + resize(window.width, window.height); +} + +void Window::hide_menu() { +RECT rc; +int width, height; + if(GetMenu(hwnd) == NULL)return; + + SetMenu(hwnd, NULL); + if(fullscreen == true) { + if(cursor_visible == true) { + ShowCursor(FALSE); + cursor_visible = false; + } + return; + } + + resize(window.width, window.height); +} + +void Window::show() { +int style; + style = GetWindowLong(hwnd, GWL_STYLE); + if(style & WS_VISIBLE)return; + ShowWindow(hwnd, SW_NORMAL); +} + +void Window::hide() { +int style; + style = GetWindowLong(hwnd, GWL_STYLE); + if(!(style & WS_VISIBLE))return; + ShowWindow(hwnd, SW_HIDE); } void Window::to_left(HWND _hwnd) { @@ -17,6 +98,8 @@ int offset = 0; if(_hwnd) { GetWindowRect(_hwnd, &rc); offset = rc.right; + } else { + offset = wa_offset.left; } GetWindowRect(hwnd, &rc); rc.left = offset; @@ -34,13 +117,14 @@ void Window::to_right() { RECT rc; GetWindowRect(hwnd, &rc); rc.left = GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left); + rc.left -= wa_offset.right; SetWindowPos(hwnd, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } void Window::to_top() { RECT rc; GetWindowRect(hwnd, &rc); - rc.top = 0; + rc.top = wa_offset.top; SetWindowPos(hwnd, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } @@ -60,34 +144,22 @@ int offset = 0; } GetWindowRect(hwnd, &rc); rc.top = GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top) - offset; + rc.top -= wa_offset.bottom; SetWindowPos(hwnd, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } -void Window::hide() { - if(visible == true) { - ShowWindow(hwnd, SW_HIDE); - visible = false; - } -} - -void Window::show() { - if(visible == false) { - ShowWindow(hwnd, SW_NORMAL); - visible = true; - } -} - -void Window::show_menu() { - SetMenu(hwnd, hmenu); - menu_visible = true; -} - -void Window::hide_menu() { - SetMenu(hwnd, 0); - menu_visible = false; -} - Window::Window() { - visible = false; - menu_visible = false; + fullscreen = false; + visible = false; + cursor_visible = true; + hmenu = NULL; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea, 0); +int sw = GetSystemMetrics(SM_CXSCREEN), + sh = GetSystemMetrics(SM_CYSCREEN); + + wa_offset.left = workarea.left; + wa_offset.top = workarea.top; + wa_offset.right = sw - workarea.right; + wa_offset.bottom = sh - workarea.bottom; } diff --git a/src/win/winmain.cpp b/src/win/winmain.cpp index 239954cc..a75a53ad 100644 --- a/src/win/winmain.cpp +++ b/src/win/winmain.cpp @@ -1,5 +1,6 @@ #define INTERFACE_MAIN -#define BSNES_VERSION "0.008" +#define BSNES_VERSION "0.009" +#define BSNES_TITLE "bsnes v" BSNES_VERSION " ~byuu" #include "winmain.h" #include "../base.h"