- [NEW] Sprites funcionant
- [NEW] OAM DMA copy funcionant
This commit is contained in:
55
gbscreen.cpp
55
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<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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user