Object rendering

This commit is contained in:
Lior Halphon 2018-03-04 23:27:31 +02:00
parent 3d1c8b50c4
commit 88a11b891f

View File

@ -6,7 +6,7 @@
/* FIFO functions */
static inline unsigned __attribute__((unused)) fifo_size(GB_fifo_t *fifo)
static inline unsigned fifo_size(GB_fifo_t *fifo)
{
return (fifo->write_end - fifo->read_end) & 0xF;
}
@ -41,6 +41,31 @@ static void fifo_push_bg_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint
}
}
static void fifo_overlay_object_row(GB_fifo_t *fifo, uint8_t lower, uint8_t upper, uint8_t palette, bool bg_priority, uint8_t priority, bool flip_x)
{
while (fifo_size(fifo) < 8) {
fifo->fifo[fifo->write_end] = (GB_fifo_item_t) {0,};
fifo->write_end++;
fifo->write_end &= 0xF;
}
uint8_t flip_xor = flip_x? 0: 0x7;
for (unsigned i = 8; i--;) {
uint8_t pixel = (lower >> 7) | ((upper >> 7) << 1);
GB_fifo_item_t *target = &fifo->fifo[(fifo->read_end + (i ^ flip_xor)) & 0xF];
if (pixel != 0 && (target->pixel == 0 || target->priority > priority)) {
target->pixel = pixel;
target->palette = palette;
target->bg_priority = bg_priority;
target->priority = priority;
}
lower <<= 1;
upper <<= 1;
}
}
/*
Each line is 456 cycles, approximately:
Mode 2 - 80 cycles / OAM Transfer
@ -444,10 +469,22 @@ static void search_oam(GB_gameboy_t *gb)
static void render_pixel_if_possible(GB_gameboy_t *gb)
{
GB_fifo_item_t *fifo_item = NULL;
GB_fifo_item_t *oam_fifo_item = NULL;
bool draw_oam = false;
bool bg_enabled = true, bg_priority = false;
if (!gb->fifo_paused) {
fifo_item = fifo_pop(&gb->bg_fifo);
}
if (fifo_size(&gb->oam_fifo)) {
oam_fifo_item = fifo_pop(&gb->oam_fifo);
if (oam_fifo_item->pixel) {
draw_oam = true;
bg_priority |= oam_fifo_item->bg_priority;
}
}
/* Drop pixels for scrollings */
if (gb->position_in_line >= 160 || gb->disable_rendering) {
gb->position_in_line++;
@ -456,26 +493,41 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
if (gb->fifo_paused) return;
/* Mixing */
bool bg_enabled = true, bg_behind = false;
if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) {
if (gb->cgb_mode) {
bg_behind = true;
bg_priority = true;
}
else {
bg_enabled = false;
}
}
if (!gb->is_cgb && gb->in_window) {
bg_enabled = true;
}
if (!bg_enabled) {
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
}
else {
uint8_t pixel = fifo_item->pixel;
if (pixel && bg_priority) {
draw_oam = false;
}
if (!gb->cgb_mode) {
pixel = ((gb->io_registers[GB_IO_BGP] >> (pixel << 1)) & 3);
}
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->background_palettes_rgb[pixel];
}
if (draw_oam) {
uint8_t pixel = oam_fifo_item->pixel;
if (!gb->cgb_mode) {
pixel = ((gb->io_registers[oam_fifo_item->palette? GB_IO_OBP1 : GB_IO_OBP0] >> (pixel << 1)) & 3);
}
gb->screen[gb->position_in_line + gb->current_line * WIDTH] = gb->sprite_palettes_rgb[oam_fifo_item->palette * 4 + pixel];
}
gb->position_in_line++;
}
@ -591,6 +643,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->cycles_for_line = MODE2_LENGTH + 4;
fifo_clear(&gb->bg_fifo);
fifo_clear(&gb->oam_fifo);
gb->position_in_line = - (gb->io_registers[GB_IO_SCX] & 7) - 8;
gb->fetcher_x = ((gb->io_registers[GB_IO_SCX]) / 8) & 0x1f;
@ -618,6 +671,32 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->fetching_objects = true;
gb->cycles_for_line += 6;
GB_SLEEP(gb, display, 20, 6);
GB_object_t *object = &objects[gb->visible_objs[gb->n_visible_objs - 1]];
bool height_16 = (gb->io_registers[GB_IO_LCDC] & 4) != 0; /* Todo: Which T-cycle actually reads this? */
uint8_t tile_y = (gb->current_line - object->y) & (height_16? 0xF : 7);
if (object->flags & 0x40) { /* Flip Y */
tile_y ^= height_16? 0xF : 7;
}
uint16_t line_address = (height_16? object->tile & 0xFE : object->tile) * 0x10 + tile_y * 2;
if (gb->cgb_mode && (object->flags & 0x8)) { /* Use VRAM bank 2 */
line_address += 0x2000;
}
uint8_t palette = (object->flags & 0x10) ? 1 : 0;
if (gb->cgb_mode) {
palette = object->flags & 0x7;
}
#if 1
fifo_overlay_object_row(&gb->oam_fifo,
gb->vram[line_address],
gb->vram[line_address + 1],
palette,
object->flags & 0x80,
gb->cgb_mode? gb->visible_objs[gb->n_visible_objs - 1] : 0,
object->flags & 0x20);
#endif
gb->n_visible_objs--;
}
gb->fetching_objects = false;