rosgb/ppu.c
2024-05-17 22:13:30 -05:00

163 lines
4.2 KiB
C

#include<inttypes.h>
#include<stdbool.h>
#include<stdio.h>
#include"gb.h"
#include"ppu.h"
#define print(x,y,str) tigrPrint(gb->ppu->info,tfont,x,y,tigrRGB(0xdd,0x66,0x77),str);
#define bit(x,n) ( ((x) & 1<<(n)) >> (n) )
#define bittest(x,y,n) (bit((x),(n))|bit((y),(n))<<1)
static uint32_t palette[4]={0x00ffffff,0x00389048,0x00284028,0x000000};
uint32_t ppu_openwindow(Ppu*ppu,uint8_t*str)
{
if(!ppu)
{
fprintf(stderr,"error: cannot open window with NULL Ppu\n");
}
ppu->info=tigrWindow(160,144,"memory",0);
ppu->screen=tigrWindow(160,144,(char*)str,0);
if(ppu->screen)ppu->pixels.t=ppu->screen->pix;
return ppu->screen==NULL||ppu->info==NULL;
}
void ppu_updatejoypad(Ppu*ppu,uint8_t*ram)
{
static uint8_t jp=0;
//R L U D
jp =(tigrKeyHeld(ppu->screen,TK_RIGHT)!=0);
jp|=(tigrKeyHeld(ppu->screen,TK_LEFT )!=0)<<1;
jp|=(tigrKeyHeld(ppu->screen,TK_UP )!=0)<<2;
jp|=(tigrKeyHeld(ppu->screen,TK_DOWN )!=0)<<3;
if(ram[0xff00]==0x20)ram[0xff00]=jp;
//A B SEL START
jp =(tigrKeyHeld(ppu->screen,'Z')!=0);
jp|=(tigrKeyHeld(ppu->screen,'X')!=0)<<1;
jp|=(tigrKeyHeld(ppu->screen,'A')!=0)<<2;//sl
jp|=(tigrKeyHeld(ppu->screen,'S')!=0)<<3;//cpu
if(ram[0xff00]==0x10)ram[0xff00]=jp;
// fprintf(stderr,"joyp (0xff00):%.2xh\n",jp);
}
void ppu_drawtile(Ppu*ppu,uint8_t x,uint8_t y,uint16_t o,uint16_t t,uint8_t *ram)
{
for(int j=0;j<16;j+=2)//bitplane
for(int i=0;i<8;i++)//bit
ppu->pixels.i[(j/2+y)*160+(i+x)]=palette[bittest(ram[o+j+t*16],ram[o+1+j+t*16],7-i)];
}
uint32_t ppu_updatewindow(struct Gb*gb,uint8_t*ram)
{
static bool tilemap=false;
static uint32_t delay=0;
if(!gb->ppu->screen||!gb->ppu->info)return 1;
delay++;
if(delay%400!=0)return 0;
if(!tigrClosed(gb->ppu->screen) && !tigrClosed(gb->ppu->info))
{
if(tigrKeyHeld(gb->ppu->screen,TK_ESCAPE)||tigrKeyHeld(gb->ppu->info,TK_ESCAPE))
return -1;
if(tigrKeyHeld(gb->ppu->screen,'Q')||tigrKeyHeld(gb->ppu->info,'Q'))
return -1;
// Draw graphical/main screen
{
tigrClear(gb->ppu->screen,tigrRGB(255,255,255));
if(tigrKeyDown(gb->ppu->screen,'P'))gb->paused=!gb->paused;
if(tigrKeyDown(gb->ppu->screen,'L'))
{
gb->log=!gb->log;
if(!gb->log)
cpu_log_clear();
}
if(tigrKeyDown(gb->ppu->screen,'M'))gb->ppu->mode=!gb->ppu->mode;
if(tigrKeyDown(gb->ppu->screen,TK_SPACE))tilemap=!tilemap;
//Draw all tiles
if(tilemap)//LCD DISPLAY ON
{
//uint16_t tilemap_select=0x9800;
//if(ram[0xff40]&0x40)tilemap_select=0x9c00;
for(int j=0;j<18;j++)//tile map veritcal
for(int i=0;i<20;i++)//tile map horizontal
ppu_drawtile(gb->ppu,i*8,j*8,0x8000,ram[0x9800+(j*0x20+i)],ram);
uint16_t oam_offs=0xfe00;//should be 0xfe00
for(int i=0;i<40;i+=4)//OAM sprites
if(ram[oam_offs+i*4]>=8&&ram[oam_offs+i*4+1]>=16)
ppu_drawtile(gb->ppu,ram[oam_offs+i*4]-8,ram[oam_offs+i*4+1]-16,0x8000,ram[oam_offs+i*4+2],ram);
}
else
// for(int i=0;i<256+128;i++)
for(int i=0;i<256;i++)
ppu_drawtile(gb->ppu,i%16*8,(i/16)*8,0x8000,i,ram);
}
// Draw information screen
{
tigrClear(gb->ppu->info,tigrRGB(0x22,0x22,0x22));
// Print mode name
static char str[128];
sprintf(str,"%s",(gb->ppu->mode==M_MEM)?("memory"):("disasm"));
print(0,0,str);
switch(gb->ppu->mode)
{
default:
case M_MEM:
{
auto uint16_t ad=0xff46;
auto uint8_t i=0;
while(i<9)
{
sprintf(str,"%.4x: %.2x %.2x %.2x %.2x %.2x %.2x",ad+i*6,ram[ad+i*6],ram[ad+i*6+1],ram[ad+i*6+2],ram[ad+i*6+3],ram[ad+i*6+4],ram[ad+i*6+5]);
print(0,12+i*12+1,str);
++i;
}
break;
}
// Can we capture from cpu_decexec at certain intervals?
// (with a buffer)
case M_DASM:
{
static char str[128];
sprintf(str,"%.4x:%s",gb->cpu->pc,cpu_log());
print(0,12,str);
sprintf(str,"log:%s",(gb->log)?"on":"off");
print(0,121,str);
break;
}
}
// All modes:
sprintf(str,"PC: %.4x%s",gb->cpu->pc,gb->paused?" [paused]":"");
print(0,133,str);
}
tigrUpdate(gb->ppu->info);
tigrUpdate(gb->ppu->screen);
}
else
return -1; //0xffffffff
return 0;
}
uint32_t ppu_closewindow(Ppu*ppu)
{
if(!ppu->screen)return 1;
tigrFree(ppu->screen);
if(!ppu->info)return 1;
tigrFree(ppu->info);
return 0;
}