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"