Update to bsnes v009 release.

- Fixed non-interlaced display modes from not drawing every other frame
    - Changed OAM halve to skip every other scanline in 224-height modes
    - Updated renderer to properly support games that switch resolutions mid-frame
    - Fixed VRAM address remapping modes, fixes DQ3R, FF: MQ
    - Fixed a bug in main color window clipping affecting BGs
    - Added video color curve option, thanks to Overload for the idea + color table
    - Added vblank, FPS counter, and DDraw surface memory options to settings menu
    - Added fullscreen modes 640x480 and 1024x768 to video modes
    - Added option to toggle the menubar on and off by pressing the escape key
    - Mode3 was not rendering sprites
    - Priorities were wrong for modes 2-4, thanks to anomie for info
    - Fixed a serious bug in IRQ interrupts. May not be perfect, but helps many games
This commit is contained in:
byuu 2005-06-26 11:07:38 +00:00
parent a471c150c9
commit 402c146a53
28 changed files with 826 additions and 354 deletions

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

123
src/win/dd_renderer16.cpp Normal file
View File

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

123
src/win/dd_renderer32.cpp Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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