Compare commits

..

2 Commits
v007 ... v008

Author SHA1 Message Date
byuu
a471c150c9 Update to bsnes v008 release.
moving the window + main color window clipping into the bg/oam/mode7 rendering routines themselves, I was able to greatly simplify the most complicated part of rendering: the final pass where color add/sub effects are applied. As a result, the new PPU core is not only ~35% faster (on graphics intensive screens, even faster on simpler screens), but more accurate as well. Awesome.
In celebration, I´m releasing bsnes v0.008. I can actually run all games I have at >60fps on my Athlon 1.67ghz PC. Probably not something to brag about, though ...
Oh, and I also updated the keyboard polling code to only capture keypresses if the main window has focus. I´ve been meaning to do this for the better part of a year now, but never got around to it.
If, for some reason, you still want to use the old renderer, you can uncomment the first line in src/ppu/bppu/bppu.h and recompile the emulator yourself. Or you can use v0.007a, I´ll leave it up for a bit.
2005-06-21 09:13:40 +00:00
byuu
ea38ea2537 Update to bsnes v007a release.
[No changelog available]
2005-06-13 04:34:10 +00:00
40 changed files with 1814 additions and 518 deletions

View File

@@ -1,4 +1,4 @@
#[bsnes v0.007 configuration file]
#[bsnes v0.007a configuration file]
#[video mode]
# 0: 256x224w
@@ -19,3 +19,9 @@ video.mode = 1
# way to guarantee that the output image will not be
# filtered.
video.use_vram = true
#video.use_vram = false
#[show fps]
# true: show fps in titlebar
# false: do not show fps in titlebar
#gui.show_fps = false

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -113,28 +113,17 @@ uint32 b, w;
}
}
void bROM::load_sram(uint8 *buffer, uint32 size) {
void bROM::load_sram(Reader *rf) {
if(rom_loaded == false)return;
if(size > sram_size) {
memcpy(sram_data, buffer, sram_size);
} else {
memset(sram_data, 0, sram_size);
memcpy(sram_data, buffer, size);
}
rf->read(&sram_data, sram_size);
}
uint32 bROM::save_sram(uint8 **buffer) {
uint8 *t;
if(rom_loaded == false)return 0;
if(!sram_size)return 0;
void bROM::save_sram(Writer *wf) {
if(rom_loaded == false)return;
if(!sram_size)return;
if(*buffer) {
t = (uint8*)memalloc(sram_size, "bROM::save_sram");
memcpy(t, sram_data, sram_size);
*buffer = t;
}
return sram_size;
wf->write(sram_data, sram_size);
}
void bROM::load_rom(Reader *rf) {
@@ -176,12 +165,6 @@ end:
case 6:sram_size = 64 * 1024;break;
case 7:sram_size = 128 * 1024;break;
}
if(sram_size) {
sram_data = (uint8*)memalloc(sram_size, "bROM::sram_data");
memset(sram_data, 0, sram_size);
} else {
sram_data = 0;
}
dprintf("Image Name : \"%s\"", cart_title);
dprintf("Image Type : %s", (mapper == LOROM)?"LoROM":"HiROM");

View File

@@ -8,13 +8,13 @@ enum { LOROM = 0, HIROM = 1 };
uint8 *data, *sram_data;
uint8 mapper;
uint32 size, sram_size;
void load_rom(Reader *rf);
void load_sram(uint8 *buffer, uint32 size);
uint32 save_sram(uint8 **buffer);
void unload();
uint8 read (uint32 addr);
void write(uint32 addr, byte value);
void write_protect(bool yn);
void load_rom(Reader *rf);
void load_sram(Reader *rf);
void save_sram(Writer *wf);
void unload();
uint8 read (uint32 addr);
void write(uint32 addr, byte value);
void write_protect(bool yn);
bROM();
~bROM();

View File

@@ -11,11 +11,11 @@ enum { WRAP_NONE = 0, WRAP_BANK = 1, WRAP_PAGE = 2 };
class ROM : public Memory {
public:
virtual void load_rom(Reader *rf) = 0;
virtual void load_sram(uint8 *buffer, uint32 size) = 0;
virtual uint32 save_sram(uint8 **buffer) = 0;
virtual void unload() = 0;
virtual void write_protect(bool yn) = 0;
virtual void load_rom(Reader *rf) = 0;
virtual void load_sram(Reader *rf) = 0;
virtual void save_sram(Writer *wf) = 0;
virtual void unload() = 0;
virtual void write_protect(bool yn) = 0;
};
class MMIO : public Memory {

View File

@@ -1,21 +1,26 @@
#include "../../base.h"
#include "bppu_mmio.cpp"
#ifdef _BPPU_OLDRENDER
#include "bppu_old_render.cpp"
#else
#include "bppu_render.cpp"
#endif
void bPPU::run() {}
void bPPU::scanline() {
uint16 v = clock->vcounter();
if(v > 0 && v < clock->visible_scanlines()) {
_y = clock->vcounter();
if(_y > 0 && _y < clock->visible_scanlines()) {
if(clock->interlace() || regs.oam_halve == true) {
output->frame_mode |= PPUOutput::INTERLACE;
output->scanline_mode[v] |= PPUOutput::INTERLACE;
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[v] |= PPUOutput::DOUBLEWIDTH;
output->frame_mode |= PPUOutput::DOUBLEWIDTH;
output->scanline_mode[_y] |= PPUOutput::DOUBLEWIDTH;
}
render_line(v);
render_line();
}
}

View File

@@ -1,3 +1,5 @@
//#define _BPPU_OLDRENDER
class bPPU;
class bPPUMMIO : public MMIO {
@@ -194,10 +196,16 @@ struct {
void latch_counters();
/* PPU render functions */
#ifdef _BPPU_OLDRENDER
#include "bppu_old_render.h"
#else
#include "bppu_render.h"
#endif
uint16 *light_table;
uint16 *mosaic_table[16];
void render_line(uint16 line);
void render_line();
/* Required functions */
void run();

View File

@@ -0,0 +1,133 @@
#include "bppu_old_render_cache.cpp"
#include "bppu_old_render_windows.cpp"
#include "bppu_old_render_main.cpp"
#include "bppu_old_render_mode7.cpp"
namespace bPPURenderTables {
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5 };
uint8 lookup_mode0[12] = {
BG4, BG3, OAM, BG4, BG3, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode1_pri0[10] = {
BG3, OAM, BG3, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode1_pri1[10] = {
BG3, OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM, BG3
};
uint8 lookup_mode2[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode3[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode4[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode5[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode6[6] = {
OAM, OAM, BG1, OAM, BG1, OAM
};
uint8 lookup_mode7[5] = {
OAM, BG1, OAM, OAM, OAM
};
uint8 lookup_mode7_extbg[6] = {
BG2, OAM, OAM, BG2, OAM, OAM
};
};
void bPPU::render_line_mode0() {
render_line_bg (7, 10, COLORDEPTH_4, BG1);
render_line_bg (6, 9, COLORDEPTH_4, BG2);
render_line_bg (1, 4, COLORDEPTH_4, BG3);
render_line_bg (0, 3, COLORDEPTH_4, BG4);
render_line_oam(2, 5, 8, 11);
set_layer_pixels(12, bPPURenderTables::lookup_mode0);
}
void bPPU::render_line_mode1() {
switch(regs.bg3_priority) {
case 0:
render_line_bg (5, 8, COLORDEPTH_16, BG1);
render_line_bg (4, 7, COLORDEPTH_16, BG2);
render_line_bg (0, 2, COLORDEPTH_4, BG3);
render_line_oam(1, 3, 6, 9);
set_layer_pixels(10, bPPURenderTables::lookup_mode1_pri0);
break;
case 1:
render_line_bg (4, 7, COLORDEPTH_16, BG1);
render_line_bg (3, 6, COLORDEPTH_16, BG2);
render_line_bg (0, 9, COLORDEPTH_4, BG3);
render_line_oam(1, 2, 5, 8);
set_layer_pixels(10, bPPURenderTables::lookup_mode1_pri1);
break;
}
}
void bPPU::render_line_mode2() {
render_line_bg (3, 6, COLORDEPTH_16, BG1);
render_line_bg (2, 5, COLORDEPTH_16, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode2);
}
void bPPU::render_line_mode3() {
render_line_bg (3, 6, COLORDEPTH_256, BG1);
render_line_bg (2, 5, COLORDEPTH_16, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode3);
}
void bPPU::render_line_mode4() {
render_line_bg (3, 6, COLORDEPTH_256, BG1);
render_line_bg (2, 5, COLORDEPTH_4, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode4);
}
void bPPU::render_line_mode5() {
render_line_bg (3, 6, COLORDEPTH_16, BG1);
render_line_bg (2, 5, COLORDEPTH_4, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode5);
}
void bPPU::render_line_mode6() {
render_line_bg (2, 4, COLORDEPTH_16, BG1);
render_line_oam(0, 1, 3, 5);
set_layer_pixels(8, bPPURenderTables::lookup_mode6);
}
void bPPU::render_line_mode7() {
if(regs.mode7_extbg == false) {
render_line_m7 (1, 0, 0); //bg2 priorities are ignored
render_line_oam(0, 2, 3, 4);
set_layer_pixels(5, bPPURenderTables::lookup_mode7);
} else {
render_line_m7 (0, 0, 3); //bg1 priority is ignored
render_line_oam(1, 2, 4, 5);
set_layer_pixels(6, bPPURenderTables::lookup_mode7_extbg);
}
}
void bPPU::render_line() {
if(regs.display_disabled == true) {
memset(output->buffer + (_y << 1) * 512, 0, 2048);
return;
}
clear_layer_cache();
clear_pixel_cache();
switch(regs.bg_mode) {
case 0:render_line_mode0();break;
case 1:render_line_mode1();break;
case 2:render_line_mode2();break;
case 3:render_line_mode3();break;
case 4:render_line_mode4();break;
case 5:render_line_mode5();break;
case 6:render_line_mode6();break;
case 7:render_line_mode7();break;
}
render_line_to_output();
}

View File

@@ -0,0 +1,70 @@
//bppu_render.cpp
void render_line_mode0();
void render_line_mode1();
void render_line_mode2();
void render_line_mode3();
void render_line_mode4();
void render_line_mode5();
void render_line_mode6();
void render_line_mode7();
//bppu_render_cache.cpp
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
enum { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 };
struct {
uint8 color_main, color_sub;
uint8 src_main, src_sub;
uint8 blend_type;
}pixel_cache[512];
uint8 layer_cache[512 * 12];
uint8 *bg_tiledata[3];
uint8 *bg_tiledata_state[3];
void clear_pixel_cache(void);
void clear_layer_cache(void);
void init_tiledata_cache(void);
void clear_tiledata_cache(void);
//bppu_render_windows.cpp
enum { WINDOWMASK_OR = 0, WINDOWMASK_AND = 1, WINDOWMASK_XOR = 2, WINDOWMASK_XNOR = 3 };
bool windows_not_obstructing(uint8 layer, uint8 bg, uint16 x);
bool color_windows_not_obstructing(uint16 x, uint8 color_mask_type);
//bppu_render_main.cpp
enum {
SH_2 = 1, SH_4 = 2, SH_8 = 3, SH_16 = 4,
SH_32 = 5, SH_64 = 6, SH_128 = 7, SH_256 = 8,
SH_512 = 9, SH_1024 = 10, SH_2048 = 11, SH_4096 = 12
};
enum { COLORMODE_ADD = 0, COLORMODE_SUB = 1 };
enum { PPU_MAIN = 0, PPU_SUB = 1 };
enum { OAM_PRI_NONE = 4 };
uint8 oam_line_pal[512], oam_line_pri[512];
struct {
byte num;
byte width, height;
word x, y;
word character;
byte v_flip, h_flip;
byte palette;
byte priority;
}current_sprite;
void render_line_to_output();
inline uint16 addsub_pixels(uint8 x, uint8 cdest_index, uint8 cdest_bg, uint8 csrc_index, uint8 csrc_bg);
inline uint16 addsub_pixel(uint8 x, uint8 cdest_index, uint8 cdest_bg);
void render_bg_tile(uint8 color_depth, uint8 bg, uint16 tile_num);
void set_pixel(uint8 bg, uint16 x, uint8 pal_index);
void set_layer_pixels(uint8 layer_count, uint8 *layer_bg_lookup);
void set_sprite_attributes(uint8 sprite_num);
void render_oam_sprite(void);
void render_line_oam(uint8 layer_pos_pri0, uint8 layer_pos_pri1, uint8 layer_pos_pri2, uint8 layer_pos_pri3);
void render_line_bg(uint8 layer_pos_pri0, uint8 layer_pos_pri1, uint8 color_depth, uint8 bg);
//bppu_render_mode7.cpp
void render_line_m7(uint8 layer_pos_bg1, uint8 layer_pos_bg2_pri0, uint8 layer_pos_bg2_pri1);

View File

@@ -0,0 +1,33 @@
//this should be reset once every scanline
void bPPU::clear_pixel_cache(void) {
for(int i=0;i<512;i++) {
pixel_cache[i].color_main = 0;
pixel_cache[i].color_sub = 0;
pixel_cache[i].src_main = BACK;
pixel_cache[i].src_sub = BACK;
pixel_cache[i].blend_type = BLENDTYPE_BACK;
}
}
//this should be reset once every scanline
void bPPU::clear_layer_cache(void) {
memset(&layer_cache, 0, 512 * 12);
}
void bPPU::init_tiledata_cache(void) {
bg_tiledata[TILE_2BIT] = (uint8*)malloc(262144);
bg_tiledata[TILE_4BIT] = (uint8*)malloc(131072);
bg_tiledata[TILE_8BIT] = (uint8*)malloc( 65536);
bg_tiledata_state[TILE_2BIT] = (uint8*)malloc( 4096);
bg_tiledata_state[TILE_4BIT] = (uint8*)malloc( 2048);
bg_tiledata_state[TILE_8BIT] = (uint8*)malloc( 1024);
}
void bPPU::clear_tiledata_cache(void) {
memset(bg_tiledata[TILE_2BIT], 0, 262144);
memset(bg_tiledata[TILE_4BIT], 0, 131072);
memset(bg_tiledata[TILE_4BIT], 0, 65536);
memset(bg_tiledata_state[TILE_2BIT], 0, 4096);
memset(bg_tiledata_state[TILE_4BIT], 0, 2048);
memset(bg_tiledata_state[TILE_8BIT], 0, 1024);
}

View File

@@ -0,0 +1,110 @@
#define CLIP_10BIT_SIGNED(x) \
((x) & ((1 << 10) - 1)) + (((((x) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
#define CAST_WORDTOINT(x) \
(int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff)))
void bPPU::render_line_m7(uint8 layer_pos_bg1, uint8 layer_pos_bg2_pri0, uint8 layer_pos_bg2_pri1) {
int x;
int step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int hoffset, voffset;
int centerx, centery;
int xx, yy;
int px, py;
int tx, ty, tile, palette, priority;
uint8 layer_pos;
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7;
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7;
centerx = (CAST_WORDTOINT(regs.m7x) << 7) >> 7;
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7;
if(regs.mode7_vflip == true) {
yy = 223 - clock->vcounter();
} else {
yy = clock->vcounter();
}
yy += CLIP_10BIT_SIGNED(voffset - centery);
m7b = CAST_WORDTOINT(regs.m7b) * yy + (centerx << 8);
m7d = CAST_WORDTOINT(regs.m7d) * yy + (centery << 8);
step_m7a = CAST_WORDTOINT(regs.m7a);
step_m7c = CAST_WORDTOINT(regs.m7c);
xx = CLIP_10BIT_SIGNED(hoffset - centerx);
m7a = CAST_WORDTOINT(regs.m7a) * xx;
m7c = CAST_WORDTOINT(regs.m7c) * xx;
for(x=0;x<256;x++) {
px = ((m7a + m7b) >> 8);
py = ((m7c + m7d) >> 8);
switch(regs.mode7_repeat) {
case 0: //screen repitition outside of screen area
case 1: //same as case 0
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
break;
case 2: //character 0 repetition outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
tx = 0;
ty = 0;
} else {
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
}
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
break;
case 3: //palette color 0 outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
palette = 0;
} else {
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
}
break;
}
if(regs.mode7_extbg == false) {
if(palette) {
layer_pos = layer_pos_bg1;
if(regs.mode7_hflip == true) {
set_layer_pixel(255 - x, palette);
} else {
set_layer_pixel(x, palette);
}
}
} else {
priority = (palette >> 7);
palette &= 0x7f;
if(palette) {
if(priority == 0) {
layer_pos = layer_pos_bg2_pri0;
} else {
layer_pos = layer_pos_bg2_pri1;
}
if(regs.mode7_hflip == true) {
set_layer_pixel(255 - x, palette);
} else {
set_layer_pixel(x, palette);
}
}
}
m7a += step_m7a;
m7c += step_m7c;
}
}

View File

@@ -0,0 +1,159 @@
bool bPPU::windows_not_obstructing(uint8 layer, uint8 bg, uint16 x) {
uint8 w1_mask, w2_mask; //1 = masked, 0 = not masked
uint16 window1_left, window1_right, window2_left, window2_right;
if(layer == PPU_MAIN) {
if(regs.bg_window_enabled[bg] == false)return true;
} else if(layer == PPU_SUB) {
if(regs.bgsub_window_enabled[bg] == false)return true;
}
window1_left = regs.window1_left;
window1_right = regs.window1_right;
window2_left = regs.window2_left;
window2_right = regs.window2_right;
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
window1_left <<= 1;
window1_right <<= 1;
window2_left <<= 1;
window2_right <<= 1;
}
if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == false) {
if(regs.bg_window1_invert[bg] == false) {
if(x >= window1_left && x <= window1_right)return false;
return true;
} else {
if(x < window1_left || x > window1_right)return false;
return true;
}
} else if(regs.bg_window2_enabled[bg] == true && regs.bg_window1_enabled[bg] == false) {
if(regs.bg_window2_invert[bg] == false) {
if(x >= window2_left && x <= window2_right)return false;
return true;
} else {
if(x < window2_left || x > window2_right)return false;
return true;
}
} else if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
if(regs.bg_window1_invert[bg] == false) {
if(x >= window1_left && x <= window1_right)w1_mask = 1;
else w1_mask = 0;
} else {
if(x < window1_left || x > window1_right)w1_mask = 1;
else w1_mask = 0;
}
if(regs.bg_window2_invert[bg] == false) {
if(x >= window2_left && x <= window2_right)w2_mask = 1;
else w2_mask = 0;
} else {
if(x < window2_left || x > window2_right)w2_mask = 1;
else w2_mask = 0;
}
switch(regs.bg_window_mask[bg]) {
case WINDOWMASK_OR:
if((w1_mask | w2_mask) == 1)return false;
return true;
case WINDOWMASK_AND:
if((w1_mask & w2_mask) == 1)return false;
return true;
case WINDOWMASK_XOR:
if((w1_mask ^ w2_mask) == 1)return false;
return true;
case WINDOWMASK_XNOR:
if((w1_mask ^ w2_mask) == 0)return false;
return true;
}
}
return true;
}
bool bPPU::color_windows_not_obstructing(uint16 x, uint8 color_mask_type) {
uint8 w1_mask, w2_mask; //1 = masked, 0 = not masked
uint8 color_mask;
bool r;
uint16 window1_left, window1_right, window2_left, window2_right;
if(color_mask_type == PPU_MAIN) {
color_mask = regs.color_mask;
} else {
color_mask = regs.colorsub_mask;
}
if(color_mask == 0)return false;
if(color_mask == 3)return true;
window1_left = regs.window1_left;
window1_right = regs.window1_right;
window2_left = regs.window2_left;
window2_right = regs.window2_right;
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
window1_left <<= 1;
window1_right <<= 1;
window2_left <<= 1;
window2_right <<= 1;
}
if(regs.color_window1_enabled == false && regs.color_window2_enabled == false) {
r = true;
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == false) {
if(regs.color_window1_invert == false) {
if(x >= window1_left && x <= window1_right)r = false;
else r = true;
} else {
if(x < window1_left || x > window1_right)r = false;
else r = true;
}
} else if(regs.color_window1_enabled == false && regs.color_window2_enabled == true) {
if(regs.color_window2_invert == false) {
if(x >= window2_left && x <= window2_right)r = false;
else r = true;
} else {
if(x < window2_left || x > window2_right)r = false;
else r = true;
}
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == true) {
if(regs.color_window1_invert == false) {
if(x >= window1_left && x <= window1_right)w1_mask = 1;
else w1_mask = 0;
} else {
if(x < window1_left || x > window1_right)w1_mask = 1;
else w1_mask = 0;
}
if(regs.color_window2_invert == false) {
if(x >= window2_left && x <= window2_right)w2_mask = 1;
else w2_mask = 0;
} else {
if(x < window2_left || x > window2_right)w2_mask = 1;
else w2_mask = 0;
}
switch(regs.color_window_mask) {
case WINDOWMASK_OR:
if((w1_mask | w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_AND:
if((w1_mask & w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_XOR:
if((w1_mask ^ w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_XNOR:
if((w1_mask ^ w2_mask) == 0)r = false;
else r = true;
break;
}
}
if(color_mask == 2) {
r = (r == true)?false:true;
}
return r;
}

View File

@@ -1,124 +1,134 @@
#include "bppu_render_cache.cpp"
#include "bppu_render_windows.cpp"
#include "bppu_render_main.cpp"
#include "bppu_render_bg.cpp"
#include "bppu_render_oam.cpp"
#include "bppu_render_mode7.cpp"
#include "bppu_render_addsub.cpp"
#include "bppu_render_line.cpp"
namespace bPPURenderTables {
enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5 };
uint8 lookup_mode0[12] = {
BG4, BG3, OAM, BG4, BG3, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode1_pri0[10] = {
BG3, OAM, BG3, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode1_pri1[10] = {
BG3, OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM, BG3
};
uint8 lookup_mode2[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode3[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode4[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode5[8] = {
OAM, OAM, BG2, BG1, OAM, BG2, BG1, OAM
};
uint8 lookup_mode6[6] = {
OAM, OAM, BG1, OAM, BG1, OAM
};
uint8 lookup_mode7[5] = {
OAM, BG1, OAM, OAM, OAM
};
uint8 lookup_mode7_extbg[6] = {
BG2, OAM, OAM, BG2, OAM, OAM
};
};
void bPPU::render_line_mode0() {
render_line_bg (7, 10, COLORDEPTH_4, BG1);
render_line_bg (6, 9, COLORDEPTH_4, BG2);
render_line_bg (1, 4, COLORDEPTH_4, BG3);
render_line_bg (0, 3, COLORDEPTH_4, BG4);
render_line_oam(2, 5, 8, 11);
set_layer_pixels(12, bPPURenderTables::lookup_mode0);
/*
Mode 0: ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
*/
inline void bPPU::render_line_mode0() {
render_line_bg(BG1, COLORDEPTH_4, 8, 11);
render_line_bg(BG2, COLORDEPTH_4, 7, 10);
render_line_bg(BG3, COLORDEPTH_4, 2, 5);
render_line_bg(BG4, COLORDEPTH_4, 1, 4);
render_line_oam(3, 6, 9, 12);
}
void bPPU::render_line_mode1() {
/*
Mode 1 (pri=0): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
Mode 1 (pri=1): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A
*/
inline void bPPU::render_line_mode1() {
switch(regs.bg3_priority) {
case 0:
render_line_bg (5, 8, COLORDEPTH_16, BG1);
render_line_bg (4, 7, COLORDEPTH_16, BG2);
render_line_bg (0, 2, COLORDEPTH_4, BG3);
render_line_oam(1, 3, 6, 9);
set_layer_pixels(10, bPPURenderTables::lookup_mode1_pri0);
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
render_line_oam(2, 4, 7, 10);
break;
case 1:
render_line_bg (4, 7, COLORDEPTH_16, BG1);
render_line_bg (3, 6, COLORDEPTH_16, BG2);
render_line_bg (0, 9, COLORDEPTH_4, BG3);
render_line_oam(1, 2, 5, 8);
set_layer_pixels(10, bPPURenderTables::lookup_mode1_pri1);
render_line_bg(BG1, COLORDEPTH_16, 5, 8);
render_line_bg(BG2, COLORDEPTH_16, 4, 7);
render_line_bg(BG3, COLORDEPTH_4, 1, 10);
render_line_oam(2, 3, 6, 9);
break;
}
}
void bPPU::render_line_mode2() {
render_line_bg (3, 6, COLORDEPTH_16, BG1);
render_line_bg (2, 5, COLORDEPTH_16, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode2);
/*
Mode 2: ->
1, 2, 3, 4, 5, 6, 7, 8
OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, 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);
}
void bPPU::render_line_mode3() {
render_line_bg (3, 6, COLORDEPTH_256, BG1);
render_line_bg (2, 5, COLORDEPTH_16, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode3);
/*
Mode 3: ->
1, 2, 3, 4, 5, 6, 7, 8
OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
*/
inline void bPPU::render_line_mode3() {
render_line_bg(BG1, COLORDEPTH_256, 4, 7);
render_line_bg(BG2, COLORDEPTH_16, 3, 6);
}
void bPPU::render_line_mode4() {
render_line_bg (3, 6, COLORDEPTH_256, BG1);
render_line_bg (2, 5, COLORDEPTH_4, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode4);
/*
Mode 4: ->
1, 2, 3, 4, 5, 6, 7, 8
OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, 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);
}
void bPPU::render_line_mode5() {
render_line_bg (3, 6, COLORDEPTH_16, BG1);
render_line_bg (2, 5, COLORDEPTH_4, BG2);
render_line_oam(0, 1, 4, 7);
set_layer_pixels(8, bPPURenderTables::lookup_mode5);
/*
Mode 5: ->
1, 2, 3, 4, 5, 6, 7, 8
OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, 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);
}
void bPPU::render_line_mode6() {
render_line_bg (2, 4, COLORDEPTH_16, BG1);
render_line_oam(0, 1, 3, 5);
set_layer_pixels(8, bPPURenderTables::lookup_mode6);
/*
Mode 6: ->
1, 2, 3, 4, 5, 6
OAM0, OAM1, BG1B, OAM2, BG1A, OAM3
*/
inline void bPPU::render_line_mode6() {
render_line_bg(BG1, COLORDEPTH_16, 3, 5);
render_line_oam(1, 2, 4, 6);
}
void bPPU::render_line_mode7() {
/*
Mode7: ->
1, 2, 3, 4, 5
OAM0, BG1n, OAM1, 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_m7 (1, 0, 0); //bg2 priorities are ignored
render_line_mode7(1, 0, 0); //bg2 priorities are ignored
render_line_oam(0, 2, 3, 4);
set_layer_pixels(5, bPPURenderTables::lookup_mode7);
} else {
render_line_m7 (0, 0, 3); //bg1 priority is ignored
render_line_mode7(0, 0, 3); //bg1 priority is ignored
render_line_oam(1, 2, 4, 5);
set_layer_pixels(6, bPPURenderTables::lookup_mode7_extbg);
}
}
void bPPU::render_line(uint16 line) {
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 + (line << 1) * 512, 0, 2048);
memset(output->buffer + (((_y << 1) + _interlace_field) << 9), 0, 1024);
return;
}
clear_layer_cache();
clear_pixel_cache();
build_color_window_tables();
switch(regs.bg_mode) {
case 0:render_line_mode0();break;
case 1:render_line_mode1();break;
@@ -129,5 +139,5 @@ void bPPU::render_line(uint16 line) {
case 6:render_line_mode6();break;
case 7:render_line_mode7();break;
}
render_line_to_output();
render_line_output();
}

View File

@@ -1,50 +1,54 @@
//bppu_render.cpp
void render_line_mode0();
void render_line_mode1();
void render_line_mode2();
void render_line_mode3();
void render_line_mode4();
void render_line_mode5();
void render_line_mode6();
void render_line_mode7();
int _screen_width;
bool _interlace;
int _interlace_field;
inline void render_line_mode0();
inline void render_line_mode1();
inline void render_line_mode2();
inline void render_line_mode3();
inline void render_line_mode4();
inline void render_line_mode5();
inline void render_line_mode6();
inline void render_line_mode7();
//bppu_render_cache.cpp
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
enum { COLORDEPTH_4 = 0, COLORDEPTH_16 = 1, COLORDEPTH_256 = 2 };
enum { TILE_2BIT = 0, TILE_4BIT = 1, TILE_8BIT = 2 };
struct {
uint8 color_main, color_sub;
uint8 src_main, src_sub;
uint8 blend_type;
enum { PC_BG1 = 0x80, PC_BG2 = 0x81, PC_BG3 = 0x82, PC_BG4 = 0x83, PC_OAM = 0x84, PC_BACK = 0x00 };
struct _pixel {
//palette # index for main/subscreen pixels
//0 = transparent / use palette color # 0
uint8 src_main, src_sub;
//indicates source of palette # for main/subscreen (BG1-4, OAM, or back)
uint8 bg_main, bg_sub;
//priority level of src_n. to set src_n,
//the priority of the pixel must be >pri_n
uint8 pri_main, pri_sub;
}pixel_cache[512];
uint8 layer_cache[512 * 12];
uint8 *bg_tiledata[3];
uint8 *bg_tiledata_state[3];
void clear_pixel_cache(void);
void clear_layer_cache(void);
void init_tiledata_cache(void);
void clear_tiledata_cache(void);
void render_bg_tile(uint8 color_depth, uint16 tile_num);
inline void clear_pixel_cache();
void init_tiledata_cache();
void clear_tiledata_cache();
//bppu_render_windows.cpp
enum { WINDOWMASK_OR = 0, WINDOWMASK_AND = 1, WINDOWMASK_XOR = 2, WINDOWMASK_XNOR = 3 };
uint8 main_windowtable[5][512], sub_windowtable[5][512],
main_colorwindowtable[512], sub_colorwindowtable[512];
bool windows_not_obstructing(uint8 layer, uint8 bg, uint16 x);
bool color_windows_not_obstructing(uint16 x, uint8 color_mask_type);
void build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen);
void build_window_tables(uint8 bg);
void build_color_window_table(uint8 *wtbl, uint8 mask);
void build_color_window_tables();
//bppu_render_main.cpp
enum {
SH_2 = 1, SH_4 = 2, SH_8 = 3, SH_16 = 4,
SH_32 = 5, SH_64 = 6, SH_128 = 7, SH_256 = 8,
SH_512 = 9, SH_1024 = 10, SH_2048 = 11, SH_4096 = 12
};
enum { COLORMODE_ADD = 0, COLORMODE_SUB = 1 };
enum { PPU_MAIN = 0, PPU_SUB = 1 };
enum { OAM_PRI_NONE = 4 };
uint8 oam_line_pal[512], oam_line_pri[512];
//bppu_render_bg.cpp
void render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos);
//bppu_render_oam.cpp
struct {
byte num;
byte width, height;
@@ -55,16 +59,23 @@ struct {
byte priority;
}current_sprite;
void render_line_to_output();
inline uint16 addsub_pixels(uint8 x, uint8 cdest_index, uint8 cdest_bg, uint8 csrc_index, uint8 csrc_bg);
inline uint16 addsub_pixel(uint8 x, uint8 cdest_index, uint8 cdest_bg);
void render_bg_tile(uint8 color_depth, uint8 bg, uint16 tile_num);
void set_pixel(uint8 bg, uint16 x, uint8 pal_index);
void set_layer_pixels(uint8 layer_count, uint8 *layer_bg_lookup);
void set_sprite_attributes(uint8 sprite_num);
void render_oam_sprite(void);
void render_line_oam(uint8 layer_pos_pri0, uint8 layer_pos_pri1, uint8 layer_pos_pri2, uint8 layer_pos_pri3);
void render_line_bg(uint8 layer_pos_pri0, uint8 layer_pos_pri1, uint8 color_depth, uint8 bg);
enum { OAM_PRI_NONE = 4 };
uint8 oam_line_pal[512], oam_line_pri[512];
void set_sprite_attributes(uint8 sprite_num);
void render_oam_sprite();
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
//bppu_render_mode7.cpp
void render_line_m7(uint8 layer_pos_bg1, uint8 layer_pos_bg2_pri0, uint8 layer_pos_bg2_pri1);
void render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri);
//bppu_render_addsub.cpp
inline uint16 addsub_pixels(int cdest_index, int cdest_bg, int csrc_index, int csrc_bg);
inline uint16 addsub_pixel(int cdest_index, int cdest_bg);
//bppu_render_line.cpp
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
inline uint16 get_palette(int index);
inline uint16 get_pixel(int x);
inline void render_line_output();

View File

@@ -0,0 +1,95 @@
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);
uint16 res;
//oam palettes 0-3 are not affected by color add/sub
if(cdest_bg == OAM) {
if(cdest_index < 192) {
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;
} 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) ));
}
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;
} 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) ));
}
break;
}
return ((r) | (g << 5) | (b << 10));
}
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);
uint16 res;
//only oam palettes 4-7 are affected by color add/sub
if(cdest_bg == OAM) {
if(cdest_index < 192) {
return cdest;
}
}
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;
} 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) ));
}
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;
} 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) ));
}
break;
}
return ((r) | (g << 5) | (b << 10));
}

View File

@@ -0,0 +1,234 @@
void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) {
return;
}
int x;
int _scaddr = regs.bg_scaddr[bg];
int _tdaddr = regs.bg_tdaddr[bg];
bool _bg_enabled = regs.bg_enabled[bg];
bool _bgsub_enabled = regs.bgsub_enabled[bg];
uint16 opt_valid_bit; //offset-per-tile valid flag bit
if(bg == BG1) {
opt_valid_bit = 0x2000;
} else if(bg == BG2) {
opt_valid_bit = 0x4000;
} else {
opt_valid_bit = 0x0000;
}
uint8 pal_size, tiledata_size;
switch(color_depth) {
case COLORDEPTH_4:
pal_size = 4;
tiledata_size = 4; //<<4=*16
break;
case COLORDEPTH_16:
pal_size = 16;
tiledata_size = 5; //<<5=*32
break;
case COLORDEPTH_256:
pal_size = 256;
tiledata_size = 6; //<<6=*64
break;
}
uint8 *bg_td, *bg_td_state;
bg_td = (uint8*)bg_tiledata[color_depth];
bg_td_state = (uint8*)bg_tiledata_state[color_depth];
uint16 screen_width, screen_height;
screen_width = _screen_width;
screen_height = _screen_width; //this is correct -- ppu tilemap is a perfect square
uint8 tile_size, tile_width, tile_height;
tile_size = (regs.bg_tilesize[bg])?4:3; //<<4=*16, <<3=*8
tile_width = tile_size;
tile_height = tile_size;
int screen_x, screen_y;
if(_interlace == true && _screen_width == 512) {
screen_y = (_y << 1) + _interlace_field;
} else {
screen_y = _y;
}
//Modes 5 and 6 seem to force 16-width tiles due to having twice the resolution.
//The tile size attribute in $2105 has no effect on tile width.
if(_screen_width == 512) {
tile_width = 4; //<<4=*16
}
if(tile_size == 4) { //16x16 tile size
screen_width <<= 1;
screen_height <<= 1;
}
if(regs.bg_scsize[bg] & 0x01)screen_width <<= 1;
if(regs.bg_scsize[bg] & 0x02)screen_height <<= 1;
uint16 screen_width_mask, screen_height_mask;
screen_width_mask = screen_width - 1;
screen_height_mask = screen_height - 1;
int bg_x, bg_y;
uint16 vscroll, hscroll;
if(_screen_width == 512) {
hscroll = (regs.bg_hofs[bg] << 1) & screen_width_mask;
} else {
hscroll = regs.bg_hofs[bg] & screen_width_mask;
}
bg_x = hscroll;
if(_screen_width == 512 && _interlace == true) {
vscroll = (regs.bg_vofs[bg] << 1) & screen_height_mask;
} else {
vscroll = regs.bg_vofs[bg] & screen_height_mask;
}
bg_y = (screen_y + vscroll) & screen_height_mask;
uint16 *mtable;
int mosaic_x, mosaic_y;
if(regs.mosaic_enabled[bg] == true) {
mtable = (uint16*)mosaic_table[regs.mosaic_size];
} else {
mtable = (uint16*)mosaic_table[0];
}
mosaic_x = mtable[bg_x];
mosaic_y = mtable[bg_y];
uint8 tile_x;
uint16 t, base_xpos, base_pos, pos;
uint16 tile_num;
int mirror_x, mirror_y;
uint8 pal_index;
uint8 *tile_ptr;
int xpos, ypos;
uint16 map_index, hoffset, voffset, col;
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);
} else {
tile_x = (mtable[screen_x + (hscroll & 7)] >> 3);
}
hoffset = hscroll;
voffset = vscroll;
if(tile_x != 0) {
tile_x = (tile_x - 1) & 31;
if(regs.bg_mode == 4) {
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
if(!(t & 0x8000)) {
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
} else {
voffset = (t & 0x1fff) & screen_height_mask;
}
}
} else {
pos = regs.bg_scaddr[BG3] + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
hoffset = ((t & 0x1ff8) | (hscroll & 7)) & screen_width_mask;
}
pos = regs.bg_scaddr[BG3] + 64 + (tile_x << 1);
t = *((uint16*)vram + (pos >> 1));
if(t & opt_valid_bit) {
voffset = (t & 0x1fff) & screen_height_mask;
}
}
}
mosaic_x = mtable[(screen_x + hoffset) & screen_width_mask ];
mosaic_y = mtable[(screen_y + voffset) & screen_height_mask];
}
switch(regs.bg_scsize[bg]) {
case 0:
map_index = 0;
break;
case 1:
map_index = ((mosaic_x >> tile_size) >> 5) << 11;
break;
case 2:
map_index = ((mosaic_y >> tile_size) >> 5) << 11;
break;
case 3:
map_index = ((mosaic_x >> tile_size) >> 5) << 11 |
((mosaic_y >> tile_size) >> 5) << 12;
break;
}
base_xpos = ((mosaic_x >> 3) & 31);
base_pos = (((mosaic_y >> tile_height) & 31) << 5) + ((mosaic_x >> tile_width) & 31);
pos = _scaddr + map_index + (base_pos << 1);
t = *((uint16*)vram + (pos >> 1));
mirror_y = (t & 0x8000)?1:0;
mirror_x = (t & 0x4000)?1:0;
int _pri;
_pri = (t & 0x2000) ? pri1_pos : pri0_pos;
tile_num = t & 0x03ff;
if(tile_width == 4) {
if(((mosaic_x & 15) >= 8 && !mirror_x) ||
((mosaic_x & 15) < 8 && mirror_x))tile_num++;
tile_num &= 0x03ff;
}
if(tile_height == 4) {
if(((mosaic_y & 15) >= 8 && !mirror_y) ||
((mosaic_y & 15) < 8 && mirror_y))tile_num += 16;
tile_num &= 0x03ff;
}
tile_num += (_tdaddr >> tiledata_size);
if(bg_td_state[tile_num] == 1) {
render_bg_tile(color_depth, tile_num);
}
pal_index = ((t >> 10) & 7) * pal_size;
if(mirror_y) { ypos = (7 - (mosaic_y & 7)); }
else { ypos = ( (mosaic_y & 7)); }
//loop while we are rendering from the same tile, as there's no need to do all of the above work
//unless we have rendered all of the visible tile, taking mosaic into account.
tile_ptr = (uint8*)bg_td + (tile_num << 6) + (ypos << 3);
while(1) {
if(mirror_x) { xpos = (7 - (mosaic_x & 7)); }
else { xpos = ( (mosaic_x & 7)); }
col = *(tile_ptr + xpos);
if(col && main_colorwindowtable[screen_x]) {
if(_bg_enabled == true && !wt_main[screen_x]) {
if(pixel_cache[screen_x].pri_main < _pri) {
pixel_cache[screen_x].pri_main = _pri;
pixel_cache[screen_x].bg_main = 0x80 | bg;
pixel_cache[screen_x].src_main = col + pal_index;
}
}
if(_bgsub_enabled == true && !wt_sub[screen_x]) {
if(pixel_cache[screen_x].pri_sub < _pri) {
pixel_cache[screen_x].pri_sub = _pri;
pixel_cache[screen_x].bg_sub = 0x80 | bg;
pixel_cache[screen_x].src_sub = col + pal_index;
}
}
}
bg_x++;
bg_x &= screen_width_mask;
mosaic_x = mtable[bg_x];
if(base_xpos != ((mosaic_x >> 3) & 31))break;
screen_x++;
if(screen_x >= _screen_width)break;
}
}
}

View File

@@ -1,30 +1,115 @@
//this should be reset once every scanline
void bPPU::clear_pixel_cache(void) {
int i;
for(i=0;i<512;i++) {
pixel_cache[i].color_main = 0;
pixel_cache[i].color_sub = 0;
pixel_cache[i].src_main = BACK;
pixel_cache[i].src_sub = BACK;
pixel_cache[i].blend_type = BLENDTYPE_BACK;
#define render_bg_tile_line_4(__m) \
col = 0; \
if(d0 & __m)col += 1; \
if(d1 & __m)col += 2; \
*dest++ = col
#define render_bg_tile_line_16(__m) \
col = 0; \
if(d0 & __m)col += 1; \
if(d1 & __m)col += 2; \
if(d2 & __m)col += 4; \
if(d3 & __m)col += 8; \
*dest++ = col
#define render_bg_tile_line_256(__m) \
col = 0; \
if(d0 & __m)col += 1; \
if(d1 & __m)col += 2; \
if(d2 & __m)col += 4; \
if(d3 & __m)col += 8; \
if(d4 & __m)col += 16; \
if(d5 & __m)col += 32; \
if(d6 & __m)col += 64; \
if(d7 & __m)col += 128; \
*dest++ = col
void bPPU::render_bg_tile(uint8 color_depth, uint16 tile_num) {
uint8 mask, d0, d1, d2, d3, d4, d5, d6, d7, col;
int x, y;
uint32 pos;
uint8 *dest;
switch(color_depth) {
case COLORDEPTH_4:
dest = (uint8*)bg_tiledata[TILE_2BIT] + tile_num * 64;
pos = tile_num * 16;
y = 8;
while(y--) {
d0 = vram[pos ];
d1 = vram[pos + 1];
render_bg_tile_line_4(0x80);
render_bg_tile_line_4(0x40);
render_bg_tile_line_4(0x20);
render_bg_tile_line_4(0x10);
render_bg_tile_line_4(0x08);
render_bg_tile_line_4(0x04);
render_bg_tile_line_4(0x02);
render_bg_tile_line_4(0x01);
pos += 2;
}
bg_tiledata_state[TILE_2BIT][tile_num] = 0;
break;
case COLORDEPTH_16:
dest = (uint8*)bg_tiledata[TILE_4BIT] + tile_num * 64;
pos = tile_num * 32;
y = 8;
while(y--) {
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
render_bg_tile_line_16(0x80);
render_bg_tile_line_16(0x40);
render_bg_tile_line_16(0x20);
render_bg_tile_line_16(0x10);
render_bg_tile_line_16(0x08);
render_bg_tile_line_16(0x04);
render_bg_tile_line_16(0x02);
render_bg_tile_line_16(0x01);
pos += 2;
}
bg_tiledata_state[TILE_4BIT][tile_num] = 0;
break;
case COLORDEPTH_256:
dest = (uint8*)bg_tiledata[TILE_8BIT] + tile_num * 64;
pos = tile_num * 64;
y = 8;
while(y--) {
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
d4 = vram[pos + 32];
d5 = vram[pos + 33];
d6 = vram[pos + 48];
d7 = vram[pos + 49];
render_bg_tile_line_256(0x80);
render_bg_tile_line_256(0x40);
render_bg_tile_line_256(0x20);
render_bg_tile_line_256(0x10);
render_bg_tile_line_256(0x08);
render_bg_tile_line_256(0x04);
render_bg_tile_line_256(0x02);
render_bg_tile_line_256(0x01);
pos += 2;
}
bg_tiledata_state[TILE_8BIT][tile_num] = 0;
break;
}
}
//this should be reset once every scanline
void bPPU::clear_layer_cache(void) {
memset(&layer_cache, 0, 512 * 12);
inline void bPPU::clear_pixel_cache() {
memset(pixel_cache, 0, sizeof(pixel_cache));
}
void bPPU::init_tiledata_cache(void) {
bg_tiledata[TILE_2BIT] = (byte*)malloc(262144);
bg_tiledata[TILE_4BIT] = (byte*)malloc(131072);
bg_tiledata[TILE_8BIT] = (byte*)malloc( 65536);
bg_tiledata_state[TILE_2BIT] = (byte*)malloc( 4096);
bg_tiledata_state[TILE_4BIT] = (byte*)malloc( 2048);
bg_tiledata_state[TILE_8BIT] = (byte*)malloc( 1024);
void bPPU::init_tiledata_cache() {
bg_tiledata[TILE_2BIT] = (uint8*)malloc(262144);
bg_tiledata[TILE_4BIT] = (uint8*)malloc(131072);
bg_tiledata[TILE_8BIT] = (uint8*)malloc( 65536);
bg_tiledata_state[TILE_2BIT] = (uint8*)malloc( 4096);
bg_tiledata_state[TILE_4BIT] = (uint8*)malloc( 2048);
bg_tiledata_state[TILE_8BIT] = (uint8*)malloc( 1024);
}
void bPPU::clear_tiledata_cache(void) {
void bPPU::clear_tiledata_cache() {
memset(bg_tiledata[TILE_2BIT], 0, 262144);
memset(bg_tiledata[TILE_4BIT], 0, 131072);
memset(bg_tiledata[TILE_4BIT], 0, 65536);

View File

@@ -0,0 +1,73 @@
inline uint16 bPPU::get_palette(int index) {
return *((uint16*)cgram + index);
}
inline uint16 bPPU::get_pixel(int x) {
_pixel *p = &pixel_cache[x];
uint16 _r;
if(p->bg_main && p->bg_sub) {
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
if(regs.addsub_mode) {
_r = addsub_pixels(p->src_main, p->bg_main & 0x7f, p->src_sub, p->bg_sub & 0x7f);
} else {
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
}
} else {
_r = get_palette(p->src_main);
}
} else if(p->bg_main) {
if(regs.bg_color_enabled[p->bg_main & 0x7f] && sub_colorwindowtable[x]) {
_r = addsub_pixel(p->src_main, p->bg_main & 0x7f);
} else {
_r = get_palette(p->src_main);
}
} else if(p->bg_sub) {
if(regs.bg_color_enabled[BACK]) {
if(sub_colorwindowtable[x]) {
if(regs.addsub_mode) {
_r = addsub_pixels(0, BACK, p->src_sub, p->bg_sub & 0x7f);
} else {
_r = addsub_pixel(0, BACK);
}
} else {
_r = get_palette(0);
}
} else {
_r = 0x0000;
}
} else {
if(main_colorwindowtable[x]) {
if(regs.bg_color_enabled[BACK] && sub_colorwindowtable[x]) {
_r = addsub_pixel(0, BACK);
} else {
_r = get_palette(0);
}
} else {
_r = 0x0000;
}
}
return _r;
}
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
uint16 *ltable;
ltable = (uint16*)light_table + (regs.display_brightness << 16);
if(_screen_width == 256) {
for(x=0;x<256;x++) {
_r = get_pixel(x);
*ptr = *(ltable + _r);
ptr += 2;
}
} else {
for(x=0;x<512;x++) {
_r = get_pixel(x);
*ptr++ = *(ltable + _r);
}
}
}

View File

@@ -4,14 +4,14 @@
#define CAST_WORDTOINT(x) \
(int)(((x & 0x8000)?(x | 0xffff0000):(x & 0x00007fff)))
void bPPU::render_line_m7(uint8 layer_pos_bg1, uint8 layer_pos_bg2_pri0, uint8 layer_pos_bg2_pri1) {
void bPPU::render_line_mode7(uint8 bg1_pri, uint8 bg2b_pri, uint8 bg2a_pri) {
int x;
int step_m7a, step_m7c, m7a, m7b, m7c, m7d;
int hoffset, voffset;
int centerx, centery;
int xx, yy;
int px, py;
int tx, ty, tile, palette, priority;
int tx, ty, tile, palette;
uint8 layer_pos;
hoffset = (CAST_WORDTOINT(regs.bg_hofs[BG1]) << 7) >> 7;
voffset = (CAST_WORDTOINT(regs.bg_vofs[BG1]) << 7) >> 7;
@@ -20,9 +20,9 @@ uint8 layer_pos;
centery = (CAST_WORDTOINT(regs.m7y) << 7) >> 7;
if(regs.mode7_vflip == true) {
yy = 223 - clock->vcounter();
yy = 223 - _y;
} else {
yy = clock->vcounter();
yy = _y;
}
yy += CLIP_10BIT_SIGNED(voffset - centery);
@@ -37,6 +37,23 @@ uint8 layer_pos;
m7a = CAST_WORDTOINT(regs.m7a) * xx;
m7c = CAST_WORDTOINT(regs.m7c) * xx;
int _pri, _x, _bg;
bool _bg_enabled, _bgsub_enabled;
if(regs.mode7_extbg == false) {
_pri = bg1_pri;
_bg = BG1;
_bg_enabled = regs.bg_enabled[BG1];
_bgsub_enabled = regs.bgsub_enabled[BG1];
} else {
_bg = BG2;
_bg_enabled = regs.bg_enabled[BG2];
_bgsub_enabled = regs.bgsub_enabled[BG2];
}
uint8 *wt_main = main_windowtable[_bg];
uint8 *wt_sub = sub_windowtable[_bg];
build_window_tables(_bg);
for(x=0;x<256;x++) {
px = ((m7a + m7b) >> 8);
py = ((m7c + m7d) >> 8);
@@ -46,10 +63,10 @@ uint8 layer_pos;
case 1: //same as case 0
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
break;
case 2: //character 0 repetition outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
@@ -58,11 +75,11 @@ uint8 layer_pos;
} else {
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
}
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
break;
case 3: //palette color 0 outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
@@ -70,40 +87,51 @@ uint8 layer_pos;
} else {
px &= 1023;
py &= 1023;
tx = ((px >> SH_8) & 127);
ty = ((py >> SH_8) & 127);
tx = ((px >> 3) & 127);
ty = ((py >> 3) & 127);
tile = vram[(ty * 128 + tx) << 1];
palette = vram[(((tile << SH_64) + ((py & 7) << SH_8) + (px & 7)) << 1) + 1];
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
}
break;
}
if(!palette)goto _end_setpixel;
if(regs.mode7_extbg == false) {
if(palette) {
layer_pos = layer_pos_bg1;
if(regs.mode7_hflip == true) {
set_layer_pixel(255 - x, palette);
} else {
set_layer_pixel(x, palette);
}
//_pri set at top of function, as it is static
if(regs.mode7_hflip == true) {
_x = 255 - x;
} else {
_x = x;
}
} else {
priority = (palette >> 7);
_pri = (palette >> 7) ? bg2a_pri : bg2b_pri;
palette &= 0x7f;
if(palette) {
if(priority == 0) {
layer_pos = layer_pos_bg2_pri0;
} else {
layer_pos = layer_pos_bg2_pri1;
if(regs.mode7_hflip == true) {
_x = 255 - x;
} else {
_x = x;
}
}
if(main_colorwindowtable[_x]) {
if(_bg_enabled == true && !wt_main[_x]) {
if(pixel_cache[_x].pri_main < _pri) {
pixel_cache[_x].pri_main = _pri;
pixel_cache[_x].bg_main = 0x80 | _bg;
pixel_cache[_x].src_main = palette;
}
if(regs.mode7_hflip == true) {
set_layer_pixel(255 - x, palette);
} else {
set_layer_pixel(x, palette);
}
if(_bgsub_enabled == true && !wt_sub[_x]) {
if(pixel_cache[_x].pri_sub < _pri) {
pixel_cache[_x].pri_sub = _pri;
pixel_cache[_x].bg_sub = 0x80 | _bg;
pixel_cache[_x].src_sub = palette;
}
}
}
_end_setpixel:
m7a += step_m7a;
m7c += step_m7c;
}

View File

@@ -0,0 +1,191 @@
void bPPU::set_sprite_attributes(uint8 sprite_num) {
uint32 t;
uint8 size, b;
uint16 x;
t = *((uint32*)oam + sprite_num);
b = oam[512 + (sprite_num >> 2)];
switch(sprite_num & 3) {
case 0: size = !!(b & 0x02); x = (b & 0x01)?0x100:0; break;
case 1: size = !!(b & 0x08); x = (b & 0x04)?0x100:0; break;
case 2: size = !!(b & 0x20); x = (b & 0x10)?0x100:0; break;
case 3: size = !!(b & 0x80); x = (b & 0x40)?0x100:0; break;
}
current_sprite.num = sprite_num;
current_sprite.priority = (t >> 28) & 3;
current_sprite.x = x | (t & 0xff);
current_sprite.y = ((t >> 8) + 1) & 0xff;
current_sprite.v_flip = !!(t & 0x80000000);
current_sprite.h_flip = !!(t & 0x40000000);
current_sprite.palette = (t >> 25) & 7;
current_sprite.character = (t >> 16) & 0x01ff;
//size: 0 = small, 1 = large
switch(regs.oam_basesize) {
case 0:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 16; current_sprite.height = 16; }
break;
case 1:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
case 2:
if(!size) { current_sprite.width = 8; current_sprite.height = 8; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 3:
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
case 4:
if(!size) { current_sprite.width = 16; current_sprite.height = 16; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 5:
if(!size) { current_sprite.width = 32; current_sprite.height = 32; }
else { current_sprite.width = 64; current_sprite.height = 64; }
break;
case 6:
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
else { current_sprite.width = 32; current_sprite.height = 64; }
break;
case 7:
if(!size) { current_sprite.width = 16; current_sprite.height = 32; }
else { current_sprite.width = 32; current_sprite.height = 32; }
break;
}
}
void bPPU::render_oam_sprite() {
uint16 pos, col, chr, tiledata_inc;
uint8 d0, d1, d2, d3, pal_index;
int x, y, z, x1, mx, mask, p;
int tile_width;
tile_width = current_sprite.width >> 3; //e.x. 16x16 sprite = 2x2 tiles
if(_interlace == true && _screen_width == 512) {
y = (_y << 1) + _interlace_field;
} else {
y = _y;
}
x = current_sprite.x;
if(_screen_width == 512) {
x <<= 1;
}
if(current_sprite.v_flip) {
y = ((current_sprite.height - 1) - (_y - current_sprite.y));
} else {
y = (_y - current_sprite.y);
}
y &= 255;
if(regs.oam_halve == true) {
y <<= 1;
y += _interlace_field;
}
chr = current_sprite.character;
tiledata_inc = (chr & 0x100)?(regs.oam_nameselect << 13):0;
chr += (y >> 3) << 4;
pal_index = (current_sprite.palette << 4);
for(x1=0;x1<tile_width;x1++) {
if(current_sprite.h_flip)mx = (tile_width - 1) - x1;
else mx = x1;
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + tiledata_inc;
d0 = vram[pos ];
d1 = vram[pos + 1];
d2 = vram[pos + 16];
d3 = vram[pos + 17];
for(z=0;z<8;z++) {
if(current_sprite.h_flip) {
mask = 0x01 << z;
} else {
mask = 0x80 >> z;
}
x &= 511;
if(x < _screen_width) {
col = 0;
if(d0 & mask)col += 1;
if(d1 & mask)col += 2;
if(d2 & mask)col += 4;
if(d3 & mask)col += 8;
if(col) {
col += pal_index;
col += 128;
if(oam_line_pri[x] == OAM_PRI_NONE) {
oam_line_pal[x] = col;
oam_line_pri[x] = current_sprite.priority;
}
if(_screen_width == 512) {
if(oam_line_pri[x + 1] == OAM_PRI_NONE) {
oam_line_pal[x + 1] = col;
oam_line_pri[x + 1] = current_sprite.priority;
}
}
}
}
x += (_screen_width == 512)?2:1;
}
}
}
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
int s;
bool _bg_enabled = regs.bg_enabled[OAM];
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
if(_bg_enabled == false && _bgsub_enabled == false)return;
uint8 *wt_main = main_windowtable[OAM];
uint8 *wt_sub = sub_windowtable[OAM];
build_window_tables(OAM);
memset(oam_line_pri, OAM_PRI_NONE, 512);
for(s=0;s<128;s++) {
set_sprite_attributes(s);
if(regs.oam_halve == false) {
if(_y >= current_sprite.y && _y < (current_sprite.y + current_sprite.height)) {
render_oam_sprite();
} else if((current_sprite.y + current_sprite.height) >= 256 && _y < ((current_sprite.y + current_sprite.height) & 255)) {
render_oam_sprite();
}
} else {
if(_y >= current_sprite.y && _y < (current_sprite.y + (current_sprite.height >> 1))) {
render_oam_sprite();
} else if((current_sprite.y + current_sprite.height) >= 256 && _y < ((current_sprite.y + (current_sprite.height >> 1)) & 255)) {
render_oam_sprite();
}
}
}
int _pri;
for(int x=0;x<_screen_width;x++) {
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
switch(oam_line_pri[x]) {
case 0:_pri = pri0_pos;break;
case 1:_pri = pri1_pos;break;
case 2:_pri = pri2_pos;break;
case 3:_pri = pri3_pos;break;
}
if(main_colorwindowtable[x]) {
if(_bg_enabled == true && !wt_main[x]) {
if(pixel_cache[x].pri_main < _pri) {
pixel_cache[x].pri_main = _pri;
pixel_cache[x].bg_main = PC_OAM;
pixel_cache[x].src_main = oam_line_pal[x];
}
}
if(_bgsub_enabled == true && !wt_sub[x]) {
if(pixel_cache[x].pri_sub < _pri) {
pixel_cache[x].pri_sub = _pri;
pixel_cache[x].bg_sub = PC_OAM;
pixel_cache[x].src_sub = oam_line_pal[x];
}
}
}
}
}

View File

@@ -1,95 +1,122 @@
bool bPPU::windows_not_obstructing(uint8 layer, uint8 bg, uint16 x) {
uint8 w1_mask, w2_mask; //1 = masked, 0 = not masked
uint16 window1_left, window1_right, window2_left, window2_right;
if(layer == PPU_MAIN) {
if(regs.bg_window_enabled[bg] == false)return true;
} else if(layer == PPU_SUB) {
if(regs.bgsub_window_enabled[bg] == false)return true;
void bPPU::build_window_table(uint8 bg, uint8 *wtbl, bool mainscreen) {
if(mainscreen == true && regs.bg_window_enabled[bg] == false) {
memset(wtbl, 0, _screen_width);
return;
}
if(mainscreen == false && regs.bgsub_window_enabled[bg] == false) {
memset(wtbl, 0, _screen_width);
return;
}
uint16 window1_left, window1_right, window2_left, window2_right;
int w1_mask, w2_mask; //1 = masked, 0 = not masked
int x;
bool r;
window1_left = regs.window1_left;
window1_right = regs.window1_right;
window2_left = regs.window2_left;
window2_right = regs.window2_right;
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
if(_screen_width == 512) {
window1_left <<= 1;
window1_right <<= 1;
window2_left <<= 1;
window2_right <<= 1;
}
if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == false) {
if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == false) {
memset(wtbl, 0, _screen_width);
} else if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == false) {
if(regs.bg_window1_invert[bg] == false) {
if(x >= window1_left && x <= window1_right)return false;
return true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window1_left && x <= window1_right)?true:false;
}
} else {
if(x < window1_left || x > window1_right)return false;
return true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x < window1_left || x > window1_right)?true:false;
}
}
} else if(regs.bg_window2_enabled[bg] == true && regs.bg_window1_enabled[bg] == false) {
} else if(regs.bg_window1_enabled[bg] == false && regs.bg_window2_enabled[bg] == true) {
if(regs.bg_window2_invert[bg] == false) {
if(x >= window2_left && x <= window2_right)return false;
return true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window2_left && x <= window2_right)?true:false;
}
} else {
if(x < window2_left || x > window2_right)return false;
return true;
}
} else if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
if(regs.bg_window1_invert[bg] == false) {
if(x >= window1_left && x <= window1_right)w1_mask = 1;
else w1_mask = 0;
} else {
if(x < window1_left || x > window1_right)w1_mask = 1;
else w1_mask = 0;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x < window2_left || x > window2_right)?true:false;
}
}
} else { //if(regs.bg_window1_enabled[bg] == true && regs.bg_window2_enabled[bg] == true) {
for(x=0;x<_screen_width;x++) {
if(regs.bg_window1_invert[bg] == false) {
w1_mask = (x >= window1_left && x <= window1_right);
} else {
w1_mask = (x < window1_left || x > window1_right);
}
if(regs.bg_window2_invert[bg] == false) {
if(x >= window2_left && x <= window2_right)w2_mask = 1;
else w2_mask = 0;
} else {
if(x < window2_left || x > window2_right)w2_mask = 1;
else w2_mask = 0;
}
if(regs.bg_window2_invert[bg] == false) {
w2_mask = (x >= window2_left && x <= window2_right);
} else {
w2_mask = (x < window2_left || x > window2_right);
}
switch(regs.bg_window_mask[bg]) {
case WINDOWMASK_OR:
if((w1_mask | w2_mask) == 1)return false;
return true;
case WINDOWMASK_AND:
if((w1_mask & w2_mask) == 1)return false;
return true;
case WINDOWMASK_XOR:
if((w1_mask ^ w2_mask) == 1)return false;
return true;
case WINDOWMASK_XNOR:
if((w1_mask ^ w2_mask) == 0)return false;
return true;
switch(regs.bg_window_mask[bg]) {
case 0: //WINDOWMASK_OR:
wtbl[x] = ((w1_mask | w2_mask) == 1)?true:false;
break;
case 1: //WINDOWMASK_AND:
wtbl[x] = ((w1_mask & w2_mask) == 1)?true:false;
break;
case 2: //WINDOWMASK_XOR:
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?true:false;
break;
case 3: //WINDOWMASK_XNOR:
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?true:false;
break;
}
}
}
return true;
}
bool bPPU::color_windows_not_obstructing(uint16 x, uint8 color_mask_type) {
uint8 w1_mask, w2_mask; //1 = masked, 0 = not masked
uint8 color_mask;
bool r;
uint16 window1_left, window1_right, window2_left, window2_right;
if(color_mask_type == PPU_MAIN) {
color_mask = regs.color_mask;
} else {
color_mask = regs.colorsub_mask;
void bPPU::build_window_tables(uint8 bg) {
build_window_table(bg, main_windowtable[bg], true);
build_window_table(bg, sub_windowtable[bg], false);
}
void bPPU::build_color_window_table(uint8 *wtbl, uint8 mask) {
if(mask == 0) {
//always
memset(wtbl, 1, _screen_width);
return;
}
if(color_mask == 0)return false;
if(color_mask == 3)return true;
if(mask == 3) {
//never
memset(wtbl, 0, _screen_width);
return;
}
int _true, _false;
if(mask == 1) {
//inside window only
_true = 1;
_false = 0;
} else { //mask == 2
//outside window only
_true = 0;
_false = 1;
}
uint16 window1_left, window1_right, window2_left, window2_right;
int w1_mask, w2_mask; //1 = masked, 0 = not masked
int x;
bool r;
window1_left = regs.window1_left;
window1_right = regs.window1_right;
window2_left = regs.window2_left;
window2_right = regs.window2_right;
if(regs.bg_mode == 5 || regs.bg_mode == 6) {
if(_screen_width == 512) {
window1_left <<= 1;
window1_right <<= 1;
window2_left <<= 1;
@@ -97,63 +124,60 @@ uint16 window1_left, window1_right, window2_left, window2_right;
}
if(regs.color_window1_enabled == false && regs.color_window2_enabled == false) {
r = true;
memset(wtbl, _false, _screen_width);
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == false) {
if(regs.color_window1_invert == false) {
if(x >= window1_left && x <= window1_right)r = false;
else r = true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window1_left && x <= window1_right)?_true:_false;
}
} else {
if(x < window1_left || x > window1_right)r = false;
else r = true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x < window1_left || x > window1_right)?_true:_false;
}
}
} else if(regs.color_window1_enabled == false && regs.color_window2_enabled == true) {
if(regs.color_window2_invert == false) {
if(x >= window2_left && x <= window2_right)r = false;
else r = true;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x >= window2_left && x <= window2_right)?_true:_false;
}
} else {
if(x < window2_left || x > window2_right)r = false;
else r = true;
}
} else if(regs.color_window1_enabled == true && regs.color_window2_enabled == true) {
if(regs.color_window1_invert == false) {
if(x >= window1_left && x <= window1_right)w1_mask = 1;
else w1_mask = 0;
} else {
if(x < window1_left || x > window1_right)w1_mask = 1;
else w1_mask = 0;
for(x=0;x<_screen_width;x++) {
wtbl[x] = (x < window2_left || x > window2_right)?_true:_false;
}
}
} else { //if(regs.color_window1_enabled == true && regs.color_window2_enabled == true) {
for(x=0;x<_screen_width;x++) {
if(regs.color_window1_invert == false) {
w1_mask = (x >= window1_left && x <= window1_right);
} else {
w1_mask = (x < window1_left || x > window1_right);
}
if(regs.color_window2_invert == false) {
if(x >= window2_left && x <= window2_right)w2_mask = 1;
else w2_mask = 0;
} else {
if(x < window2_left || x > window2_right)w2_mask = 1;
else w2_mask = 0;
}
if(regs.color_window2_invert == false) {
w2_mask = (x >= window2_left && x <= window2_right);
} else {
w2_mask = (x < window2_left || x > window2_right);
}
switch(regs.color_window_mask) {
case WINDOWMASK_OR:
if((w1_mask | w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_AND:
if((w1_mask & w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_XOR:
if((w1_mask ^ w2_mask) == 1)r = false;
else r = true;
break;
case WINDOWMASK_XNOR:
if((w1_mask ^ w2_mask) == 0)r = false;
else r = true;
break;
switch(regs.color_window_mask) {
case 0: //WINDOWMASK_OR:
wtbl[x] = ((w1_mask | w2_mask) == 1)?_true:_false;
break;
case 1: //WINDOWMASK_AND:
wtbl[x] = ((w1_mask & w2_mask) == 1)?_true:_false;
break;
case 2: //WINDOWMASK_XOR:
wtbl[x] = ((w1_mask ^ w2_mask) == 1)?_true:_false;
break;
case 3: //WINDOWMASK_XNOR:
wtbl[x] = ((w1_mask ^ w2_mask) == 0)?_true:_false;
break;
}
}
}
if(color_mask == 2) {
r = (r == true)?false:true;
}
return r;
}
void bPPU::build_color_window_tables() {
build_color_window_table(main_colorwindowtable, regs.color_mask);
build_color_window_table(sub_colorwindowtable, regs.colorsub_mask);
}

View File

@@ -14,6 +14,7 @@ uint16 *buffer;
class PPU {
public:
int _y;
PPUOutput *output;
MMIO *mmio;
virtual uint8 vram_read (uint16 addr) = 0;

View File

@@ -1,24 +1,38 @@
#include "../base.h"
bool FileReader::open(char *fn) {
/* is the filename too short to be a file? */
if(strlen(fn) < 4)return false;
uint32 FileReader::size() {
return fsize;
}
int i;
for(i=strlen(fn) - 1;i>=0;i--) {
if(fn[i] == '.')break;
/*
This function will allocate memory even if open() fails.
This is needed so that when SRAM files do not exist, the
memory for the SRAM data will be allocated still.
The memory is flushed to 0x00 when no file is opened.
*/
void FileReader::read(uint8 **buffer, uint32 length) {
uint8 *data;
if(length == 0) {
/* read the entire file into RAM */
data = (uint8*)memalloc(fsize);
memset(data, 0, fsize);
if(fp)fread(data, 1, fsize, fp);
} else if(length > fsize) {
/* read the entire file into RAM, pad the rest with 0x00s */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, fsize, fp);
} else { //fsize >= length
/* read as much of the file as possible, truncate the rest */
data = (uint8*)memalloc(length);
memset(data, 0, length);
if(fp)fread(data, 1, length, fp);
}
if(fn[i] != '.')return false;
char *filetype = fn + i;
/* make sure we support this file format before loading it */
if(stricmp(filetype, ".smc") &&
stricmp(filetype, ".swc") &&
stricmp(filetype, ".fig") &&
stricmp(filetype, ".ufo") &&
stricmp(filetype, ".gd3") &&
stricmp(filetype, ".078"))return false;
*buffer = data;
}
bool FileReader::open(uint8 type, char *fn) {
fp = fopen(fn, "rb");
if(!fp)return false;
@@ -26,12 +40,7 @@ char *filetype = fn + i;
fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(!stricmp(filetype, ".smc") ||
!stricmp(filetype, ".swc") ||
!stricmp(filetype, ".fig") ||
!stricmp(filetype, ".ufo") ||
!stricmp(filetype, ".gd3") ||
!stricmp(filetype, ".078")) {
if(type == TYPE_ROM) {
/* remove header if it exists */
if((fsize & 0xfff) == 0x200) {
fsize -= 0x200;
@@ -48,29 +57,23 @@ char *filetype = fn + i;
return true;
}
void FileReader::read(uint8 **buffer, uint32 length) {
uint8 *data;
if(length == 0) {
/* read the entire file into RAM */
data = (uint8*)memalloc(fsize);
fread(data, 1, fsize, fp);
} else if(length > fsize) {
/* read the entire file into RAM, pad the rest with 0x00s */
data = (uint8*)memalloc(length);
memset(data, 0, length);
fread(data, 1, fsize, fp);
} else { //fsize >= length
/* read as much of the file as possible, truncate the rest */
data = (uint8*)memalloc(length);
fread(data, 1, length, fp);
}
*buffer = data;
}
uint32 FileReader::size() {
return fsize;
}
void FileReader::close() {
if(fp)fclose(fp);
}
void FileWriter::write(uint8 *buffer, uint32 length) {
if(!fp)return;
fwrite(buffer, 1, length, fp);
}
bool FileWriter::open(char *fn) {
fp = fopen(fn, "wb");
if(!fp)return false;
return true;
}
void FileWriter::close() {
if(fp)fclose(fp);
}

View File

@@ -10,11 +10,33 @@ FILE *fp;
uint32 fsize;
public:
enum {
TYPE_ROM = 0,
TYPE_SRAM = 1
};
uint32 size();
void read(uint8 **buffer, uint32 length = 0);
bool open(char *fn);
bool open(uint8 type, char *fn);
void close();
FileReader() { fp = 0; fsize = 0; }
~FileReader() { if(fp)fclose(fp); }
};
class Writer {
public:
virtual void write(uint8 *buffer, uint32 length);
};
class FileWriter : public Writer {
private:
FILE *fp;
public:
void write(uint8 *buffer, uint32 length);
bool open(char *fn);
void close();
FileWriter() { fp = 0; }
~FileWriter() { if(fp)fclose(fp); }
};

View File

@@ -1,5 +1,5 @@
CC = cl
CFLAGS = /nologo /O2 /Ob2
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs
OBJS = winmain.obj \
libstring.obj libconfig.obj \
clock.obj bclock.obj \

View File

@@ -86,7 +86,7 @@ void bSNES::run() {
}
void bSNES::render_frame() {
renderer->update();
dd_renderer->update();
}
/***********************
@@ -94,18 +94,21 @@ void bSNES::render_frame() {
***********************/
#define KeyState(key) ((GetAsyncKeyState(key) & 0x8000)?1:0)
void bSNES::poll_input() {
joypad1.up = KeyState(VK_UP);
joypad1.down = KeyState(VK_DOWN);
joypad1.left = KeyState(VK_LEFT);
joypad1.right = KeyState(VK_RIGHT);
joypad1.select = KeyState(VK_LSHIFT) | KeyState(VK_RSHIFT);
joypad1.start = KeyState(VK_RETURN);
joypad1.y = KeyState('A');
joypad1.b = KeyState('Z');
joypad1.x = KeyState('S');
joypad1.a = KeyState('X');
joypad1.l = KeyState('D');
joypad1.r = KeyState('C');
/* Only capture input when main window has focus */
if(GetForegroundWindow() == w_main->hwnd) {
joypad1.up = KeyState(VK_UP);
joypad1.down = KeyState(VK_DOWN);
joypad1.left = KeyState(VK_LEFT);
joypad1.right = KeyState(VK_RIGHT);
joypad1.select = KeyState(VK_LSHIFT) | KeyState(VK_RSHIFT);
joypad1.start = KeyState(VK_RETURN);
joypad1.y = KeyState('A');
joypad1.b = KeyState('Z');
joypad1.x = KeyState('S');
joypad1.a = KeyState('X');
joypad1.l = KeyState('D');
joypad1.r = KeyState('C');
}
//Check for debugger-based key locks
if(is_debugger_enabled == true) {

View File

@@ -8,8 +8,13 @@ struct {
uint32 use_vram;
}video;
struct {
uint32 show_fps;
}gui;
Config() {
__config_add(video.mode, 1, DEC);
__config_add(video.use_vram, true, TRUEFALSE);
__config_add(gui.show_fps, true, TRUEFALSE);
}
}cfg;

View File

@@ -1,19 +1,13 @@
//This is in the global namespace for inline assembly optimizations.
//If it were in a class, I would have to cast a pointer to it, and
//to read from a pointer array requires an extra opcode:
//mov eax,[array+eax*4] -> lea ebx,[parray] ; mov ebx,[ebx+eax*4]
uint32 color_lookup_table[65536];
Render::Render() {
DDRenderer::DDRenderer() {
lpdd = 0;
lpdds = 0;
lpddsb = 0;
lpddc = 0;
}
void Render::update_color_lookup_table() {
void DDRenderer::update_color_lookup_table() {
int i, r, g, b;
lpdds->GetSurfaceDesc(&ddsd);
lpddsb->GetSurfaceDesc(&ddsd);
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
if(color_depth == 15) {
for(i=0;i<65536;i++) {
@@ -45,9 +39,66 @@ int i, r, g, b;
}
}
void Render::set_window(HWND hwnd_handle) { hwnd = hwnd_handle; }
void DDRenderer::set_window(HWND hwnd_handle) { hwnd = hwnd_handle; }
void Render::to_windowed() {
/*
This function tries to create a 16-bit backbuffer whenever possible,
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.
*/
void DDRenderer::create_backbuffer() {
int color_depth;
lpdds->GetSurfaceDesc(&ddsd);
color_depth = ddsd.ddpfPixelFormat.dwRGBBitCount;
if(color_depth == 15 || color_depth == 16) {
goto try_native_backbuffer;
} else {
if(cfg.video.use_vram == false) {
goto try_native_backbuffer;
}
}
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(cfg.video.use_vram) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
} else {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
ddsd.dwWidth = 512;
ddsd.dwHeight = 478;
ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
ddsd.ddpfPixelFormat.dwRBitMask = 0xf800;
ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0;
ddsd.ddpfPixelFormat.dwBBitMask = 0x001f;
if(lpdd->CreateSurface(&ddsd, &lpddsb, 0) == DD_OK)return;
try_native_backbuffer:
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(cfg.video.use_vram) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
} else {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
ddsd.dwWidth = 512;
ddsd.dwHeight = 478;
lpdd->CreateSurface(&ddsd, &lpddsb, 0);
}
void DDRenderer::to_windowed() {
destroy();
DirectDrawCreate(0, &lpdd, 0);
lpdd->SetCooperativeLevel(hwnd, DDSCL_NORMAL);
@@ -62,24 +113,12 @@ void Render::to_windowed() {
lpddc->SetHWnd(0, hwnd);
lpdds->SetClipper(lpddc);
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(cfg.video.use_vram) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
} else {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
ddsd.dwWidth = 512;
ddsd.dwHeight = 478;
lpdd->CreateSurface(&ddsd, &lpddsb, 0);
create_backbuffer();
update_color_lookup_table();
update();
}
void Render::to_fullscreen() {
void DDRenderer::to_fullscreen() {
destroy();
DirectDrawCreate(0, &lpdd, 0);
lpdd->SetCooperativeLevel(hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
@@ -95,24 +134,12 @@ void Render::to_fullscreen() {
lpddc->SetHWnd(0, hwnd);
lpdds->SetClipper(lpddc);
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if(cfg.video.use_vram) {
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
} else {
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
ddsd.dwWidth = 512;
ddsd.dwHeight = 478;
lpdd->CreateSurface(&ddsd, &lpddsb, 0);
create_backbuffer();
update_color_lookup_table();
update();
}
void Render::set_source_window(RECT *rs) {
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;
@@ -121,7 +148,7 @@ void Render::set_source_window(RECT *rs) {
}
}
void Render::redraw() {
void DDRenderer::redraw() {
RECT rd, rs;
POINT p;
HRESULT hr;
@@ -136,6 +163,7 @@ HRESULT hr;
lpddsb->Restore();
}
if(cfg.gui.show_fps == false)return;
uint32 fps;
char s[256], t[256];
fps_timer->tick();
@@ -155,7 +183,7 @@ char s[256], t[256];
}
}
void Render::update16() {
void DDRenderer::update16() {
HRESULT hr;
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0);
if(hr != DD_OK)return;
@@ -227,7 +255,7 @@ int x, y;
lpddsb->Unlock(0);
}
void Render::update32() {
void DDRenderer::update32() {
HRESULT hr;
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0);
if(hr != DD_OK)return;
@@ -299,7 +327,7 @@ int x, y;
lpddsb->Unlock(0);
}
void Render::update() {
void DDRenderer::update() {
switch(color_depth) {
case 15:
case 16:
@@ -312,7 +340,7 @@ void Render::update() {
redraw();
}
void Render::destroy() {
void DDRenderer::destroy() {
if(lpddc) {
lpddc->Release();
lpddc = 0;

27
src/win/dd_renderer.h Normal file
View File

@@ -0,0 +1,27 @@
#include <ddraw.h>
class DDRenderer {
public:
LPDIRECTDRAW lpdd;
LPDIRECTDRAWSURFACE lpdds, lpddsb;
LPDIRECTDRAWCLIPPER lpddc;
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
HWND hwnd;
uint8 color_depth;
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 redraw();
void update16();
void update32();
void update();
void destroy();
void update_color_lookup_table();
DDRenderer();
};
DDRenderer *dd_renderer;

View File

@@ -67,32 +67,3 @@ va_list args;
w_console->write(str, Console::DEBUG_MESSAGE);
}
}
uint32 load_file(char *fn, uint8 **buffer) {
FILE *fp;
uint8 *data;
int fsize;
fp = fopen(fn, "rb");
if(!fp)return 0;
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
if(!fsize) {
fclose(fp);
return 0;
}
fseek(fp, 0, SEEK_SET);
data = (uint8*)memalloc(fsize);
fread(data, 1, fsize, fp);
fclose(fp);
*buffer = data;
return fsize;
}
bool save_file(char *fn, uint8 *data, uint32 size) {
FILE *fp;
fp = fopen(fn, "wb");
if(!fp)return false;
fwrite(data, 1, size, fp);
fclose(fp);
return true;
}

View File

@@ -22,23 +22,19 @@ bool ROMImage::load() {
dprintf("* Loading [%s]...", rom_fn);
Reader *rf = new FileReader();
FileReader *f_rf = static_cast<FileReader*>(rf);
if(!f_rf->open(rom_fn)) {
FileReader *rf = new FileReader();
if(!rf->open(FileReader::TYPE_ROM, rom_fn)) {
alert("Error loading image file [%s]!", rom_fn);
return false;
}
mem_bus->rom->load_rom(rf);
f_rf->close();
delete rf;
mem_bus->rom->load_rom(static_cast<Reader*>(rf));
rf->close();
uint8 *sram_data;
uint32 sram_size;
sram_size = load_file(sram_fn, &sram_data);
if(sram_size) {
mem_bus->rom->load_sram(sram_data, sram_size);
memfree(sram_data);
}
rf->open(FileReader::TYPE_SRAM, sram_fn);
mem_bus->rom->load_sram(static_cast<Reader*>(rf));
rf->close();
delete(rf);
file_loaded = true;
bsnes->debugger_activate();
@@ -48,13 +44,12 @@ uint32 sram_size;
void ROMImage::unload() {
if(file_loaded == false)return;
uint8 *sram_data;
uint32 sram_size;
sram_size = mem_bus->rom->save_sram(&sram_data);
if(sram_size) {
save_file(sram_fn, sram_data, sram_size);
memfree(sram_data);
}
FileWriter *wf = new FileWriter();
wf->open(sram_fn);
mem_bus->rom->save_sram(static_cast<Writer*>(wf));
wf->close();
delete(wf);
file_loaded = false;
bsnes->debugger_deactivate();

View File

@@ -1,7 +1,7 @@
HFONT hFont, hMonofont;
#include "dd_renderer.cpp"
#include "ui_window.cpp"
#include "ui_render.cpp"
#include "ui_main.cpp"
#include "ui_console.cpp"
#include "ui_bp.cpp"
@@ -29,18 +29,18 @@ void CreateWindows() {
}
void init_ui0() {
renderer = new Render();
w_main = new MainWindow();
w_console = new Console();
w_bp = new BreakpointEditor();
w_memory = new MemoryEditor();
dd_renderer = new DDRenderer();
w_main = new MainWindow();
w_console = new Console();
w_bp = new BreakpointEditor();
w_memory = new MemoryEditor();
}
void init_ui1() {
CreateFonts();
CreateWindows();
SetFocus(w_main->hwnd);
renderer->set_window(w_main->hwnd);
renderer->to_windowed();
dd_renderer->set_window(w_main->hwnd);
dd_renderer->to_windowed();
bsnes->debugger_deactivate();
}

View File

@@ -225,28 +225,3 @@ uint32 edit_mode, edit_addr, edit_mask;
};
MemoryEditor *w_memory;
#include <ddraw.h>
class Render {
public:
LPDIRECTDRAW lpdd;
LPDIRECTDRAWSURFACE lpdds, lpddsb;
LPDIRECTDRAWCLIPPER lpddc;
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
HWND hwnd;
uint8 color_depth;
void set_window(HWND hwnd_handle);
void to_windowed();
void to_fullscreen();
void set_source_window(RECT *rs);
void redraw();
void update16();
void update32();
void update();
void destroy();
void update_color_lookup_table();
Render();
};
Render *renderer;

View File

@@ -137,7 +137,7 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
PostQuitMessage(0);
break;
case WM_PAINT:
renderer->redraw();
dd_renderer->redraw();
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);

View File

@@ -1,5 +1,5 @@
#define INTERFACE_MAIN
#define BSNES_VERSION "0.007"
#define BSNES_VERSION "0.008"
#include "winmain.h"
#include "../base.h"
@@ -7,6 +7,7 @@
#include "bsnes.h"
#include "ui.h"
#include "dd_renderer.h"
#include "timer.cpp"
fpstimer *fps_timer;
@@ -34,11 +35,18 @@ void term_snes() {
if(snes) { delete(snes); snes = 0; }
}
void get_config_fn(string &str) {
char *t = (char*)malloc(4096);
_getcwd(t, 4095);
str = t;
free(t);
str += "\\bsnes.cfg";
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
string cfg_fn;
_getcwd(cfg_fn, 4096);
cfg_fn += "\\bsnes.cfg";
get_config_fn(cfg_fn);
cfg.load(cfg_fn);
meminit();
fps_timer = new fpstimer();