diff --git a/gbscreen.cpp b/gbscreen.cpp index 61001c6..aa7e2ef 100644 --- a/gbscreen.cpp +++ b/gbscreen.cpp @@ -169,29 +169,69 @@ namespace gbscreen struct oam_entry_t { - uint8_t y, tile, attr; + uint8_t y, x, tile, attr; }; + oam_entry_t *oam = nullptr; void fill_line_buffer_obj(uint8_t LY) { const uint8_t LCDC = mem::readMem(0xff40); if ((LCDC & 0x2) == 0) return; + oam = (oam_entry_t*)mem::rawPtr(0xfe00); const uint8_t height = (LCDC & 0x4) ? 16 : 8; uint8_t obj_list[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; int num_obj_found=0; int obj=0; - while (obj<40 && num_obj_found<10) - { - const uint8_t y = mem::readMem(0xff00+(obj*4)); - if ( (LY>=y) && (LY= (oam[obj].y)) && (LY+16 < (oam[obj].y+height)) ) { obj_list[num_obj_found]=obj; - uint8_t i = num_obj_found; - while( (i>0) && (obj_list[i-1]) ) num_obj_found++; } obj++; } + // Pintem els sprites en el buffer de sprites + uint8_t pixels[160]; + uint8_t x_pos[160]; + for (int i=0;i<160;++i) { pixels[i] = 0; x_pos[i] = 255; } + obj=0; + while (obj_list[obj] != 255) { + oam_entry_t *o = &oam[obj_list[obj]]; + const uint8_t ly = uint8_t(LY-o->y) & 0x7; + + uint16_t tile = height==8 ? o->tile : o->tile & 0xFE; // si es dos tiles de alt, el primer sempre comença en numero parell + uint8_t yflip = o->attr&0x40 ? 8-ly : ly; // està invertit verticalment? + uint16_t tile_address = 0x8000 + (tile<<4) + (yflip*2); + + uint8_t a = mem::readMem(tile_address); + uint8_t b = mem::readMem(tile_address+1); + + for (int i=0; i<8; ++i) { // Per a cada pixel de la linea del tile... + if (o->x+i>=168) break; // Si ja estem fora de la pantalla per la dreta, eixim del bucle + if (o->x+i>=8) { // Si està dins de la pantalla... + if (x_pos[o->x+i-8]>o->x) { // Si te una x menor que la que tenía + //uint8_t xflip = o->attr&0x20 ? 8 : 0; // està invertit horitzontalment? + uint8_t ppos = 1 << ( o->attr&0x20 ? i : 7-i); + uint8_t val = (a&ppos ? 1 : 0) + (b&ppos ? 2 : 0 ); // agafem el pixel que toca + if (val) { // Si el pixel no es transparent... + pixels[o->x+i-8] = val | o->attr&0x80; // el pintem al buffer, amb el flag de prioritat respecte al BKG + x_pos[o->x+i-8] = o->x; // I apuntem la seua x per a comparar després + } + } + } + } + obj++; + } + // Per últim, volquem els pixels que toque al buffer de linea + for (int i=0; i<160; ++i) { + if (pixels[i]>0) { // si el pixel no es transparent... + if ( !(pixels[i]&0x80) || (line_buffer[i]==0) ) { // Si te prioritat o el color de fondo es 0... + line_buffer[i] = pixels[i]&0x03; // pintem el pixel (llevant el flag de prioritat) + } + } + } } void refresh(const uint32_t dt, const bool full) @@ -244,6 +284,7 @@ namespace gbscreen STAT = (STAT & 0xFC) | 0x02; // Set mode 2 if (STAT&0x20) stat_interrupt = true; fill_line_buffer_bkg(LY); + fill_line_buffer_obj(LY); } else if (LY==154) { diff --git a/mbc_none.cpp b/mbc_none.cpp index 9567ff3..772787b 100644 --- a/mbc_none.cpp +++ b/mbc_none.cpp @@ -71,6 +71,7 @@ namespace mbc_none } else { if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room if ( (address==0xFF00) ) { value = value & 0x30; } + if ( (address==0xFF46) ) mem::init_dma_transfer(value); hram[address - 0xFE00] = value; } } @@ -95,6 +96,24 @@ namespace mbc_none } + uint8_t* rawPtr(uint16_t address) + { + if (address < 0x8000) { + if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[address]; + return &rom[address]; + } else if (address < 0xA000) { + return &vram[address - 0x8000]; + } else if (address < 0xC000) { + return &exram[address - 0xA000]; + } else if (address < 0xE000) { + return &wram[address - 0xC000]; + } else if (address < 0xFE00) { + return &wram[address - 0xE000]; + } else { + return &hram[address - 0XFE00]; + } + } + void reset() { FILE *f = fopen("dmg_boot.bin", "rb"); @@ -121,6 +140,7 @@ namespace mbc_none mem::saveState = mbc_none::saveState; mem::loadState = mbc_none::loadState; mem::reset = mbc_none::reset; + mem::rawPtr = mbc_none::rawPtr; mbc_none::rom = rom; diff --git a/mem.cpp b/mem.cpp index ef8db7e..9995521 100644 --- a/mem.cpp +++ b/mem.cpp @@ -12,9 +12,14 @@ namespace mem void (*setTag)(uint16_t, uint8_t); void (*saveState)(FILE*); void (*loadState)(FILE*); - + uint8_t*(*rawPtr)(uint16_t); + char *title = nullptr; + uint16_t dma_address = 0; + uint8_t dma_pos = 160; + uint16_t dma_dots = 0; + void init(uint8_t* rom, const int size) { //if (memory) free(memory); @@ -33,4 +38,23 @@ namespace mem }; } + void init_dma_transfer(uint8_t source) + { + dma_address = source << 8; + dma_pos = 0; + dma_dots = 0; + } + + void update_mapped(const uint32_t dt) + { + if (dma_pos<160) { + dma_dots += dt; + while (dma_dots >= 4 && dma_pos<160) { + dma_dots -= 4; + mem::writeMem(0xfe00|dma_pos, mem::readMem(dma_address|dma_pos)); + dma_pos++; + } + } + } + } diff --git a/mem.h b/mem.h index 588da94..1ce6bab 100644 --- a/mem.h +++ b/mem.h @@ -35,4 +35,9 @@ namespace mem extern void (*saveState)(FILE*); extern void (*loadState)(FILE*); + + extern uint8_t*(*rawPtr)(uint16_t); + + void init_dma_transfer(uint8_t source); + void update_mapped(const uint32_t dt); } diff --git a/sm83.cpp b/sm83.cpp index 3a0dd6e..bc33957 100644 --- a/sm83.cpp +++ b/sm83.cpp @@ -1009,6 +1009,7 @@ namespace sm83 debug::setcursor(rPC); debug::history::store(); + mem::update_mapped(t); return t; }