- [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)
|
||||
{
|
||||
|
||||
20
mbc_none.cpp
20
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;
|
||||
|
||||
|
||||
24
mem.cpp
24
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
5
mem.h
5
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user