- [NEW] Sprites funcionant

- [NEW] OAM DMA copy funcionant
This commit is contained in:
2025-01-24 14:52:36 +01:00
parent 771136e712
commit 8c8afa220f
5 changed files with 99 additions and 8 deletions

View File

@@ -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<y+height) ) {
// Revisem els 40 posibles sprites o fins a trobar 10...
while (obj<40 && num_obj_found<10) {
// Si el sprite està tocant la linea actual l'afegim a la llista
if ( (LY+16 >= (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)
{