- [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
|
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)
|
void fill_line_buffer_obj(uint8_t LY)
|
||||||
{
|
{
|
||||||
const uint8_t LCDC = mem::readMem(0xff40);
|
const uint8_t LCDC = mem::readMem(0xff40);
|
||||||
if ((LCDC & 0x2) == 0) return;
|
if ((LCDC & 0x2) == 0) return;
|
||||||
|
|
||||||
|
oam = (oam_entry_t*)mem::rawPtr(0xfe00);
|
||||||
const uint8_t height = (LCDC & 0x4) ? 16 : 8;
|
const uint8_t height = (LCDC & 0x4) ? 16 : 8;
|
||||||
uint8_t obj_list[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
|
uint8_t obj_list[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
|
||||||
int num_obj_found=0;
|
int num_obj_found=0;
|
||||||
int obj=0;
|
int obj=0;
|
||||||
while (obj<40 && num_obj_found<10)
|
// Revisem els 40 posibles sprites o fins a trobar 10...
|
||||||
{
|
while (obj<40 && num_obj_found<10) {
|
||||||
const uint8_t y = mem::readMem(0xff00+(obj*4));
|
// Si el sprite està tocant la linea actual l'afegim a la llista
|
||||||
if ( (LY>=y) && (LY<y+height) ) {
|
if ( (LY+16 >= (oam[obj].y)) && (LY+16 < (oam[obj].y+height)) ) {
|
||||||
obj_list[num_obj_found]=obj;
|
obj_list[num_obj_found]=obj;
|
||||||
uint8_t i = num_obj_found;
|
|
||||||
while( (i>0) && (obj_list[i-1]) )
|
|
||||||
num_obj_found++;
|
num_obj_found++;
|
||||||
}
|
}
|
||||||
obj++;
|
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)
|
void refresh(const uint32_t dt, const bool full)
|
||||||
@@ -244,6 +284,7 @@ namespace gbscreen
|
|||||||
STAT = (STAT & 0xFC) | 0x02; // Set mode 2
|
STAT = (STAT & 0xFC) | 0x02; // Set mode 2
|
||||||
if (STAT&0x20) stat_interrupt = true;
|
if (STAT&0x20) stat_interrupt = true;
|
||||||
fill_line_buffer_bkg(LY);
|
fill_line_buffer_bkg(LY);
|
||||||
|
fill_line_buffer_obj(LY);
|
||||||
}
|
}
|
||||||
else if (LY==154)
|
else if (LY==154)
|
||||||
{
|
{
|
||||||
|
|||||||
20
mbc_none.cpp
20
mbc_none.cpp
@@ -71,6 +71,7 @@ namespace mbc_none
|
|||||||
} else {
|
} else {
|
||||||
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
|
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
|
||||||
if ( (address==0xFF00) ) { value = value & 0x30; }
|
if ( (address==0xFF00) ) { value = value & 0x30; }
|
||||||
|
if ( (address==0xFF46) ) mem::init_dma_transfer(value);
|
||||||
hram[address - 0xFE00] = 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()
|
void reset()
|
||||||
{
|
{
|
||||||
FILE *f = fopen("dmg_boot.bin", "rb");
|
FILE *f = fopen("dmg_boot.bin", "rb");
|
||||||
@@ -121,6 +140,7 @@ namespace mbc_none
|
|||||||
mem::saveState = mbc_none::saveState;
|
mem::saveState = mbc_none::saveState;
|
||||||
mem::loadState = mbc_none::loadState;
|
mem::loadState = mbc_none::loadState;
|
||||||
mem::reset = mbc_none::reset;
|
mem::reset = mbc_none::reset;
|
||||||
|
mem::rawPtr = mbc_none::rawPtr;
|
||||||
|
|
||||||
mbc_none::rom = rom;
|
mbc_none::rom = rom;
|
||||||
|
|
||||||
|
|||||||
26
mem.cpp
26
mem.cpp
@@ -12,9 +12,14 @@ namespace mem
|
|||||||
void (*setTag)(uint16_t, uint8_t);
|
void (*setTag)(uint16_t, uint8_t);
|
||||||
void (*saveState)(FILE*);
|
void (*saveState)(FILE*);
|
||||||
void (*loadState)(FILE*);
|
void (*loadState)(FILE*);
|
||||||
|
uint8_t*(*rawPtr)(uint16_t);
|
||||||
|
|
||||||
char *title = nullptr;
|
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)
|
void init(uint8_t* rom, const int size)
|
||||||
{
|
{
|
||||||
//if (memory) free(memory);
|
//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 (*saveState)(FILE*);
|
||||||
extern void (*loadState)(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