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.
This commit is contained in:
byuu 2005-06-21 09:13:40 +00:00
parent ea38ea2537
commit a471c150c9
29 changed files with 1700 additions and 385 deletions

View File

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

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

@ -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.007a"
#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;