Gb, Cpu, Ppu modules, general refactoring

This commit is contained in:
corey 2024-05-17 11:31:29 -05:00
parent 53d1e6904c
commit b2a1b5909f
11 changed files with 1657 additions and 1591 deletions

View File

@ -1,33 +1,33 @@
# General
CC= /usr/lib/mingw64-toolchain/bin/x86_64-w64-mingw32-gcc
CFLAGS= -Wfatal-errors
LDFLAGS= -luser32 -lshell32 -ladvapi32 -ld3d9
OBJS= main.o cpu.o ppu.o tigr/tigr.o bittest.o
NASMFLAGS= -fwin64
# Tigr
CFLAGS += -I ./tigr/
# ifeq ($(OS),Windows_NT)
LDFLAGS += -s -lopengl32 -lgdi32
# else
# UNAME_S := $(shell uname -s)
# ifeq ($(UNAME_S),Darwin)
# LDFLAGS += -framework OpenGL -framework Cocoa
# else ifeq ($(UNAME_S),Linux)
# LDFLAGS += -s -lGLU -lGL -lX11
# endif
# endif
# Targets
all: rosgb
rosgb: $(OBJS)
$(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.c %.h
$(CC) -c $< -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.c
$(CC) -c $^ -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.asm
nasm $(NASMFLAGS) $^ -o $@
clean:
$(RM) *.o $(OBJS) rosgb rosgb.exe
# General
CC= /usr/lib/mingw64-toolchain/bin/x86_64-w64-mingw32-gcc
CFLAGS= -Wfatal-errors
LDFLAGS= -luser32 -lshell32 -ladvapi32 -ld3d9
NASMFLAGS= -fwin64
OBJS= main.o tigr/tigr.o cpu.o ppu.o gb.o
# Tigr
CFLAGS += -I ./tigr/
# ifeq ($(OS),Windows_NT)
LDFLAGS += -s -lopengl32 -lgdi32
# else
# UNAME_S := $(shell uname -s)
# ifeq ($(UNAME_S),Darwin)
# LDFLAGS += -framework OpenGL -framework Cocoa
# else ifeq ($(UNAME_S),Linux)
# LDFLAGS += -s -lGLU -lGL -lX11
# endif
# endif
# Targets
all: rosgb
rosgb: $(OBJS)
$(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.c %.h
$(CC) -c $< -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.c
$(CC) -c $^ -o $@ $(CFLAGS) $(LDFLAGS)
%.o: %.asm
nasm $(NASMFLAGS) $^ -o $@
clean:
$(RM) *.o $(OBJS) rosgb rosgb.exe

View File

@ -1,8 +0,0 @@
#include<stdint.h>
#define bit(x,n) ( ((x) & 1<<(n)) >> (n) )
uint8_t bittest(uint8_t a,uint8_t b,uint8_t bit)
{
return ( bit(a,bit) | ( bit(b,bit) <<1 ) );
}

2066
cpu.c

File diff suppressed because it is too large Load Diff

24
cpu.h
View File

@ -5,20 +5,28 @@
#include<stdlib.h>
#include<inttypes.h>
struct Cpu;
#include"ppu.h"
#define F_Z 0x80//zero flag
#define F_N 0x40//subtract
#define F_H 0x20//half-carry
#define F_C 0x10//carry
typedef struct St //cpu state
#define ror(x,n) ((x>>n)|(x<<((sizeof(x)<<3)-n)))
// Cpu state
typedef struct Cpu
{
uint8_t a,f,b,c,d,e,h,l; //regs signed, flags unsigned
uint16_t sp,pc;
uint8_t ime;
}St;
} Cpu;
void decexec(St *st,uint8_t *rom,uint8_t *op,uint8_t *ram);
void decexecCB(uint8_t*st,uint8_t *rom,uint8_t *op,uint8_t *ram);
void fetch16(St *st,uint8_t *rom,uint16_t *u16,uint8_t *ram);
void fetch8(St *st,uint8_t *rom,uint8_t *u8,uint8_t *ram);
void romhexdump(uint8_t *rom);
void write_ram(uint16_t addr,uint8_t val,St *st,uint8_t *ram);
void cpu_decexec(Cpu*cpu,struct Ppu*ppu,uint8_t*rom,uint8_t*op,uint8_t*ram);
void cpu_decexecCB(uint8_t*cpu,uint8_t*rom,uint8_t*op,uint8_t*ram);
void cpu_fetch16(Cpu*cpu,uint8_t*rom,uint16_t*u16,uint8_t*ram);
void cpu_fetch8(Cpu*cpu,uint8_t*rom,uint8_t*u8,uint8_t*ram);
void cpu_romhexdump(uint8_t*rom);
void cpu_write_ram(Cpu*cpu,struct Ppu*ppu,uint16_t addr,uint8_t val,uint8_t*ram);

88
gb.c Normal file
View File

@ -0,0 +1,88 @@
#include"gb.h"
Gb gb_new(void)
{
Gb gb=(Gb){0};
gb.cpu=malloc(sizeof(struct Cpu));
if(!gb.cpu)
{
fprintf(stderr,"error: failed to allocate Cpu\n");
return gb;
}
*(gb.cpu)=(struct Cpu){.sp=0xfe,.pc=0x100,.ime=1};
gb.ppu=malloc(sizeof(struct Ppu));
if(!gb.ppu)
{
fprintf(stderr,"error: failed to allocate Ppu\n");
free(gb.cpu);
gb.cpu=NULL;
return gb;
}
return gb;
}
void gb_free(Gb*gb)
{
if(!gb)
{
fprintf(stderr,"error: cannot free NULL Gb\n");
return;
}
if(gb->cpu)free(gb->cpu);
gb->cpu=NULL;
if(gb->ppu)free(gb->ppu);
gb->ppu=NULL;
if(gb->ram)free(gb->ram);
gb->ram=NULL;
if(gb->rom)free(gb->rom);
gb->rom=NULL;
}
void gb_print_cpu_state(Gb*gb)
{
if(!gb)
{
fprintf(stderr,"error: cannot print Cpu state with NULL Gb\n");
return;
}
printf("\n----------\nCPU State:");
for(int i=0;i<8;i++)
{
printf("\n%c=","afbcdehl"[i]);
uint16_t r=0;
switch(i)
{
default:
case 0:r=gb->cpu->a;break;
case 1:r=gb->cpu->f;break;
case 2:r=gb->cpu->b;break;
case 3:r=gb->cpu->c;break;
case 4:r=gb->cpu->d;break;
case 5:r=gb->cpu->e;break;
case 6:r=gb->cpu->h;break;
case 7:r=gb->cpu->l;break;
}
printf("%12u (%#4.2x)",r,r);
}
printf("\nsp: %.4x\npc: %.4x\n",gb->cpu->sp,gb->cpu->pc);
printf("IME: %.2x\n",gb->cpu->ime);
printf("f: (%x) Z:%x N:%x H:%x C:%x\n",gb->cpu->f>>4,(gb->cpu->f&F_Z)>>4,(gb->cpu->f&F_N)>>4,(gb->cpu->f&F_H)>>4,(gb->cpu->f&F_C)>>4);
printf("INT: (%.2x) V-B:%.2x LCD:%.2x TIM:%.2x SER:%.2x JOYP:%.2x\n",gb->ram[0xffff],gb->ram[0xffff]&0x1,gb->ram[0xffff]>>1&0x1,gb->ram[0xffff]>>2&0x1,gb->ram[0xffff]>>3&0x1,gb->ram[0xffff]>>4&0x1);
printf("STACK: ");for(int i=0xfffe;i>0xffee;i--)printf("%.2x ",gb->ram[i]);
printf("\nTILE 0(RAM): ");for(int i=0;i<8;i++)printf("%.2x ",gb->ram[0x8000+i]);
// {
// printf("\nTilemap:%.2x,%.2x\n",(uint8_t)gb->ram[0x9800],(uint8_t)gb->ram[0x9801]);
// FILE *fp=fopen("tilemap.txt","w");
// for(int i=0;i<0x800;i++)//lines
// {
// fprintf(fp,"%.2x,",gb->ram[0x9800+i]);
// if(i%32==0 && i!=0)fputc('\n',fp);
// }
// // fwrite(gb->ram+0x9800,1,0x800,fp);
// fclose(fp);
// }
printf("\nOAM Sprite 0 Tile: %.2x X: %.2x Y: %.2x",gb->ram[0xfe02],gb->ram[0xfe00],gb->ram[0xfe01]);
printf("\nOAM Sprite 1 Tile: %.2x X: %.2x Y: %.2x",gb->ram[0xfe06],gb->ram[0xfe04],gb->ram[0xfe05]);
printf("\nOAM Sprite 16 Tile: %.2x X: %.2x Y: %.2x",gb->ram[0xfe12],gb->ram[0xfe10],gb->ram[0xfe11]);
}

22
gb.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include<stdint.h>
#include"cpu.h"
#include"ppu.h"
typedef struct Gb
{
struct Cpu*cpu;
struct Ppu*ppu;
uint32_t nclocks;
uint32_t romsize;
uint8_t *ram;
uint8_t *rom;
uint8_t op;
uint8_t paused;
} Gb;
Gb gb_new(void);
void gb_free(Gb*gb);
void gb_print_cpu_state(Gb*gb);

127
main.c
View File

@ -7,141 +7,106 @@
#include<time.h>
#include"cpu.h"
#include"ppu.h"
#include"gb.h"
#define VIDEO
//#define PRINTING
#define F_Z 0x80//zero flag
#define F_N 0x40//subtract
#define F_H 0x20//half-carry
#define F_C 0x10//carry
uint8_t st[16];
uint8_t paused=false;
bool paused=false;
int main(int c,char **v)
{
St *stp=(St*)st;
uint8_t op;
uint8_t *ram;
FILE *f=fopen(v[1],"rb");
uint8_t *rom;
uint32_t romsize;
st[8]=0xfe;//sp
st[9]=0xff;
Gb gb=gb_new();
uint32_t nclocks=clock();
if(!gb.cpu)goto quit;
if(!gb.ppu)goto quit;
ram=malloc(0x10000);
if(!ram)return 3;
gb.nclocks=clock();
gb.paused=false;
gb.ram=malloc(0x10000);
if(!gb.ram)goto quit;
if(c<2 || !f)return 1;
// fseek(f,0x100,SEEK_SET);
//copy to memory
fseek(f,0,SEEK_END);
romsize=ftell(f);
if(0x8000>romsize)romsize=0x8000;
rom=malloc(romsize);
gb.romsize=ftell(f);
if(0x8000>gb.romsize)gb.romsize=0x8000;
gb.rom=malloc(gb.romsize);
if(!rom)return 2;
if(!gb.rom)return 2;
rewind(f);
fread(rom,1,romsize,f);
printf("Loaded ROM \'%s\' (%u B)\n",v[1],romsize);
fread(gb.rom,1,gb.romsize,f);
printf("Loaded ROM \'%s\' (%u B)\n",v[1],gb.romsize);
printf("ROM Size: %ukB\n",32<<rom[0x148]);
printf("RAM Size: %ukB\n",16<<rom[0x149]*2);
printf("ROM Size: %ukB\n",32<<gb.rom[0x148]);
printf("RAM Size: %ukB\n",16<<gb.rom[0x149]*2);
if(c>2 && strcmp(v[2],"-d")==0)
{
romhexdump(rom);
cpu_romhexdump(gb.rom);
return 0;
}
st[10]=0x00;//0x100
st[11]=0x01;
//load program into RAM
for(int i=0;i<0x8000;i++)
{
ram[i]=rom[i];
assert(ram[i]==rom[i]);
gb.ram[i]=gb.rom[i];
assert(gb.ram[i]==gb.rom[i]);
}
printf("Loaded 8000h (32768) bytes into RAM\n");
// Open window
#ifdef VIDEO
openwindow(rom+0x134);
ppu_openwindow(gb.ppu,gb.rom+0x134);
#endif
ram[0xff4f]=0;//VRAM bank
st[12]=1;//IME enable interrupts
// for(int i=0;i<70&&((st[10]|st[11]<<8)<romsize);i++)
gb.ram[0xff4f]=0;//VRAM bank
// for(int i=0;i<70&&((gb.cpu.pc)<gb.romsize);i++)
//-----CPU CYCLE LOOP-----
for(;;)
{
#ifdef VIDEO
if(updatewindow(ram,stp))break;
if(ppu_updatewindow(gb.ppu,gb.cpu,gb.ram))break;
#endif
if(paused)continue;
if(/*gb.*/paused)continue;
//Control Registers--
ram[0xff44]+=1;//CURLINE (VBLANK INT AT:144-153)
//ram[0xff05]+=1;//TIMA (TIMER INT AT OVERFLOW)
// if(!ram[0xff05])ram[0xff05]=ram[0xff06];
ram[0xff41]=(ram[0xff41]+1)%4;//V-BLANK
gb.ram[0xff44]+=1;//CURLINE (VBLANK INT AT:144-153)
//gb.ram[0xff05]+=1;//TIMA (TIMER INT AT OVERFLOW)
// if(!gb.ram[0xff05])gb.ram[0xff05]=gb.ram[0xff06];
gb.ram[0xff41]=(gb.ram[0xff41]+1)%4;//V-BLANK
//Interrupts--
//if(ram[0xff44]==144 && ram[0xffff] && st[12])//V-BLANK INT
//if(gb.ram[0xff44]==144 && gb.ram[0xffff] && gb.cpu.ime)//V-BLANK INT
//{
// stp->sp-=2;//push pc, jump to 0040h interrupt
// write_ram(stp->sp,stp->pc&0x00ff,stp,ram);
// write_ram(stp->sp+1,stp->pc>>8,stp,ram);
// stp->pc=0x0040;
// gb.cpu.sp-=2;//push pc, jump to 0040h interrupt
// cpu_write_ram(gb.cpu,gb.ppu,gb.cpu.sp,gb.cpu.pc&0x00ff,gb.ram);
// cpu_write_ram(gb.cpu,gb.ppu,gb.cpu.sp+1,gb.cpu.pc>>8,gb.ram);
// gb.cpu.pc=0x0040;
//}
//if(stp->pc==0xff82)MessageBoxA(NULL,"FF82","-",MB_OK);
//if(gb.cpu.pc==0xff82)MessageBoxA(NULL,"FF82","-",MB_OK);
#ifdef PRINTING
printf("\n[%#10.8x]%#5.2x: ",st[10]|st[11]<<8,rom[st[10]|st[11]<<8]);
printf("\n[%#10.8x]%#5.2x: ",gb.cpu.pc,gb.rom[gb.cpu.pc]);
#endif
fetch8(stp,rom,&op,ram);
decexec(stp,rom,&op,ram);
cpu_fetch8(gb.cpu,gb.rom,&gb.op,gb.ram);
cpu_decexec(gb.cpu,gb.ppu,gb.rom,&gb.op,gb.ram);
}
printf("\n----------\nCPU State:");
for(int i=0;i<8;i++)printf("\n%c=%12u (%#4.2x)","afbcdehl"[i],st[i],st[i]);
printf("\nsp: %.4x\npc: %.4x\n",st[8]|st[9]<<8,st[10]|st[11]<<8);
printf("IME: %.2x\n",st[12]);
printf("f: (%x) Z:%x N:%x H:%x C:%x\n",st[1]>>4,(st[1]&F_Z)>>4,(st[1]&F_N)>>4,(st[1]&F_H)>>4,(st[1]&F_C)>>4);
printf("INT: (%.2x) V-B:%.2x LCD:%.2x TIM:%.2x SER:%.2x JOYP:%.2x\n",ram[0xffff],ram[0xffff]&0x1,ram[0xffff]>>1&0x1,ram[0xffff]>>2&0x1,ram[0xffff]>>3&0x1,ram[0xffff]>>4&0x1);
printf("STACK: ");for(int i=0xfffe;i>0xffee;i--)printf("%.2x ",ram[i]);
printf("\nTILE 0(RAM): ");for(int i=0;i<8;i++)printf("%.2x ",ram[0x8000+i]);
// {
// printf("\nTilemap:%.2x,%.2x\n",(uint8_t)ram[0x9800],(uint8_t)ram[0x9801]);
// FILE *fp=fopen("tilemap.txt","w");
// for(int i=0;i<0x800;i++)//lines
// {
// fprintf(fp,"%.2x,",ram[0x9800+i]);
// if(i%32==0 && i!=0)fputc('\n',fp);
// }
// // fwrite(ram+0x9800,1,0x800,fp);
// fclose(fp);
// }
printf("\nOAM Sprite 0 Tile: %.2x X: %.2x Y: %.2x",ram[0xfe02],ram[0xfe00],ram[0xfe01]);
printf("\nOAM Sprite 1 Tile: %.2x X: %.2x Y: %.2x",ram[0xfe06],ram[0xfe04],ram[0xfe05]);
printf("\nOAM Sprite 16 Tile: %.2x X: %.2x Y: %.2x",ram[0xfe12],ram[0xfe10],ram[0xfe11]);
free(ram);
free(rom);
#ifdef VIDEO
closewindow();
#endif
quit:
gb_print_cpu_state(&gb);
#ifdef VIDEO
ppu_closewindow(gb.ppu);
#endif
gb_free(&gb);
}

108
ppu.c
View File

@ -4,69 +4,65 @@
#include<inttypes.h>
#include<stdbool.h>
#define print(x,y,str) tigrPrint(tpInfo,tfont,x,y,tigrRGB(0xdd,0x66,0x77),str);
extern uint8_t bittest(uint8_t b1,uint8_t b2,uint8_t bit);
#define print(x,y,str) tigrPrint(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};
extern uint8_t paused;
static union _i{TPixel *t;uint32_t *i;}_i;
static union _i im;
static Tigr *tp,*tpInfo;
uint32_t openwindow(uint8_t*str)
uint32_t ppu_openwindow(Ppu*ppu,uint8_t*str)
{
tpInfo=tigrWindow(160,144,"memory",0);
tp=tigrWindow(160,144,str,0);
if(tp)im.t=tp->pix;
return tp==NULL||tpInfo==NULL;
if(!ppu)
{
fprintf(stderr,"error: cannot open window with NULL Ppu\n");
}
ppu->info=tigrWindow(160,144,"memory",0);
ppu->screen=tigrWindow(160,144,str,0);
if(ppu->screen)ppu->pixels.t=ppu->screen->pix;
return ppu->screen==NULL||ppu->info==NULL;
}
void updatejoypad(uint8_t*ram)
void ppu_updatejoypad(Ppu*ppu,uint8_t*ram)
{
static uint8_t jp=0;
//R L U D
jp =(tigrKeyHeld(tp,TK_RIGHT)!=0);
jp|=(tigrKeyHeld(tp,TK_LEFT )!=0)<<1;
jp|=(tigrKeyHeld(tp,TK_UP )!=0)<<2;
jp|=(tigrKeyHeld(tp,TK_DOWN )!=0)<<3;
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(tp,'Z')!=0);
jp|=(tigrKeyHeld(tp,'X')!=0)<<1;
jp|=(tigrKeyHeld(tp,'A')!=0)<<2;//sl
jp|=(tigrKeyHeld(tp,'S')!=0)<<3;//st
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 DrawTile(uint8_t x,uint8_t y,uint16_t o,uint16_t t,uint8_t *ram)
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
im.i[(j/2+y)*160+(i+x)]=palette[bittest(ram[o+j+t*16],ram[o+1+j+t*16],7-i)];
ppu->pixels.i[(j/2+y)*160+(i+x)]=palette[bittest(ram[o+j+t*16],ram[o+1+j+t*16],7-i)];
}
uint8_t tilemap=false;
uint32_t updatewindow(uint8_t*ram,St*st)
uint32_t ppu_updatewindow(Ppu*ppu,struct Cpu*cpu,uint8_t*ram)
{
static bool tilemap=false;
static uint32_t delay=0;
if(!tp||!tpInfo)return 1;
if(!ppu->screen||!ppu->info)return 1;
delay++;
if(delay%400!=0)return 0;
if(!tigrClosed(tp)&&!tigrKeyHeld(tp,TK_ESCAPE)&&!tigrClosed(tpInfo)&&!tigrKeyHeld(tpInfo,TK_ESCAPE))
if(!tigrClosed(ppu->screen)&&!tigrKeyHeld(ppu->screen,TK_ESCAPE)&&!tigrClosed(ppu->info)&&!tigrKeyHeld(ppu->info,TK_ESCAPE))
{
tigrClear(tp,tigrRGB(255,255,255));
tigrClear(tpInfo,tigrRGB(0x22,0x22,0x22));
if(tigrKeyDown(tp,'P'))paused=!paused;
if(tigrKeyDown(tp,TK_SPACE))
{
printf("SPACE-----------------------------------------------------\n");
tilemap=!tilemap;
}
tigrClear(ppu->screen,tigrRGB(255,255,255));
tigrClear(ppu->info,tigrRGB(0x22,0x22,0x22));
if(tigrKeyDown(ppu->screen,'P'))paused=!paused;
if(tigrKeyDown(ppu->screen,TK_SPACE))tilemap=!tilemap;
//Draw all tiles
if(tilemap)//LCD DISPLAY ON
{
@ -74,45 +70,45 @@ uint32_t updatewindow(uint8_t*ram,St*st)
//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
DrawTile(i*8,j*8,0x8000,ram[0x9800+(j*0x20+i)],ram);
ppu_drawtile(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)
DrawTile(ram[oam_offs+i*4]-8,ram[oam_offs+i*4+1]-16,0x8000,ram[oam_offs+i*4+2],ram);
ppu_drawtile(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++)
DrawTile(i%16*8,(i/16)*8,0x8000,i,ram);
ppu_drawtile(ppu,i%16*8,(i/16)*8,0x8000,i,ram);
// for(int i=0;i<0xff;i++)
{
static char str[128];
auto uint16_t ad=0xff46;
auto uint8_t i=0;
info:
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,i*12+1,str);
if(i++<9)goto info;
sprintf(str,"PC: %.4x%s",st->pc,paused?" [paused]":"");
info:
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,i*12+1,str);
if(i++<9)goto info;
sprintf(str,"PC: %.4x%s",cpu->pc,paused?" [paused]":"");
print(0,1+i*12,str);
}
tigrUpdate(tpInfo);
tigrUpdate(tp);
tigrUpdate(ppu->info);
tigrUpdate(ppu->screen);
}
else
return -1; //0xffffffff
return 0;
}
uint32_t closewindow()
uint32_t ppu_closewindow(Ppu*ppu)
{
if(!tp)return 1;
tigrFree(tp);
if(!tpInfo)return 1;
tigrFree(tpInfo);
if(!ppu->screen)return 1;
tigrFree(ppu->screen);
if(!ppu->info)return 1;
tigrFree(ppu->info);
return 0;
}

23
ppu.h
View File

@ -5,10 +5,21 @@
#include<stdio.h>
#include<inttypes.h>
#include<stdbool.h>
#include"cpu.h"
uint32_t closewindow();
uint32_t openwindow(uint8_t*str);
uint32_t updatewindow(uint8_t*ram,St*st);
void DrawTile(uint8_t x,uint8_t y,uint16_t o,uint16_t t,uint8_t *ram);
void updatejoypad(uint8_t*ram);
struct Ppu;
#include"cpu.h"
#include"gb.h"
typedef struct Ppu
{
union{TPixel*t;uint32_t*i;}pixels;
Tigr*screen;
Tigr*info;
} Ppu;
uint32_t ppu_closewindow(Ppu*ppu);
uint32_t ppu_openwindow(Ppu*ppu,uint8_t*str);
void ppu_drawtile(Ppu*ppu,uint8_t x,uint8_t y,uint16_t o,uint16_t t,uint8_t *ram);
void ppu_updatejoypad(Ppu*ppu,uint8_t*ram);
uint32_t ppu_updatewindow(Ppu*ppu,struct Cpu*cpu,uint8_t*ram);

View File

@ -4,6 +4,4 @@
#### build
Windows:
build
make

View File

@ -1,356 +1,356 @@
// TIGR - TIny GRaphics Library - v3.1
// ^^ ^^
//
// rawr.
/*
This is free and unencumbered software released into the public domain.
Our intent is that anyone is free to copy and use this software,
for any purpose, in any form, and by any means.
The authors dedicate any and all copyright interest in the software
to the public domain, at their own expense for the betterment of mankind.
The software is provided "as is", without any kind of warranty, including
any implied warranty. If it breaks, you get to keep both pieces.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Compiler configuration.
#ifdef _MSC_VER
#define TIGR_INLINE static __forceinline
#else
#define TIGR_INLINE static inline
#endif
// Bitmaps ----------------------------------------------------------------
// This struct contains one pixel.
typedef struct {
unsigned char r, g, b, a;
} TPixel;
// Window flags.
#define TIGR_FIXED 0 // window's bitmap is a fixed size (default)
#define TIGR_AUTO 1 // window's bitmap is scaled with the window
#define TIGR_2X 2 // always enforce (at least) 2X pixel scale
#define TIGR_3X 4 // always enforce (at least) 3X pixel scale
#define TIGR_4X 8 // always enforce (at least) 4X pixel scale
#define TIGR_RETINA 16 // enable retina support on OS X
#define TIGR_NOCURSOR 32 // hide cursor
#define TIGR_FULLSCREEN 64 // start in full-screen mode
// A Tigr bitmap.
typedef struct Tigr {
int w, h; // width/height (unscaled)
int cx, cy, cw, ch; // clip rect
TPixel *pix; // pixel data
void *handle; // OS window handle, NULL for off-screen bitmaps.
int blitMode; // Target bitmap blit mode
} Tigr;
// Creates a new empty window with a given bitmap size.
//
// Title is UTF-8.
//
// In TIGR_FIXED mode, the window is made as large as possible to contain an integer-scaled
// version of the bitmap while still fitting on the screen. Resizing the window will adapt
// the scale in integer steps to fit the bitmap.
//
// In TIGR_AUTO mode, the initial window size is set to the bitmap size times the pixel
// scale. Resizing the window will resize the bitmap using the specified scale.
// For example, in forced 2X mode, the window will be twice as wide (and high) as the bitmap.
//
// Turning on TIGR_RETINA mode will request full backing resolution on OSX, meaning that
// the effective window size might be integer scaled to a larger size. In TIGR_AUTO mode,
// this means that the Tigr bitmap will change size if the window is moved between
// retina and non-retina screens.
//
Tigr *tigrWindow(int w, int h, const char *title, int flags);
// Creates an empty off-screen bitmap.
Tigr *tigrBitmap(int w, int h);
// Deletes a window/bitmap.
void tigrFree(Tigr *bmp);
// Returns non-zero if the user requested to close a window.
int tigrClosed(Tigr *bmp);
// Displays a window's contents on-screen and updates input.
void tigrUpdate(Tigr *bmp);
// Called before doing direct OpenGL calls and before tigrUpdate.
// Returns non-zero if OpenGL is available.
int tigrBeginOpenGL(Tigr *bmp);
// Sets post shader for a window.
// This replaces the built-in post-FX shader.
void tigrSetPostShader(Tigr *bmp, const char* code, int size);
// Sets post-FX properties for a window.
//
// The built-in post-FX shader uses the following parameters:
// p1: hblur - use bilinear filtering along the x-axis (pixels)
// p2: vblur - use bilinear filtering along the y-axis (pixels)
// p3: scanlines - CRT scanlines effect (0-1)
// p4: contrast - contrast boost (1 = no change, 2 = 2X contrast, etc)
void tigrSetPostFX(Tigr *bmp, float p1, float p2, float p3, float p4);
// Drawing ----------------------------------------------------------------
// Helper for reading pixels.
// For high performance, just access bmp->pix directly.
TPixel tigrGet(Tigr *bmp, int x, int y);
// Plots a pixel.
// Clips and blends.
// For high performance, just access bmp->pix directly.
void tigrPlot(Tigr *bmp, int x, int y, TPixel pix);
// Clears a bitmap to a color.
// No blending, no clipping.
void tigrClear(Tigr *bmp, TPixel color);
// Fills a rectangular area.
// No blending, no clipping.
void tigrFill(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Draws a line.
// Start pixel is drawn, end pixel is not.
// Clips and blends.
void tigrLine(Tigr *bmp, int x0, int y0, int x1, int y1, TPixel color);
// Draws an empty rectangle.
// Drawing a 1x1 rectangle yields the same result as calling tigrPlot.
// Clips and blends.
void tigrRect(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Fills a rectangle.
// Fills the inside of the specified rectangular area.
// Calling tigrRect followed by tigrFillRect using the same arguments
// causes no overdrawing.
// Clips and blends.
void tigrFillRect(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Draws a circle.
// Drawing a zero radius circle yields the same result as calling tigrPlot.
// Drawing a circle with radius one draws a circle three pixels wide.
// Clips and blends.
void tigrCircle(Tigr *bmp, int x, int y, int r, TPixel color);
// Fills a circle.
// Fills the inside of the specified circle.
// Calling tigrCircle followed by tigrFillCircle using the same arguments
// causes no overdrawing.
// Filling a circle with zero radius has no effect.
// Clips and blends.
void tigrFillCircle(Tigr *bmp, int x, int y, int r, TPixel color);
// Sets clip rect.
// Set to (0, 0, -1, -1) to reset clipping to full bitmap.
void tigrClip(Tigr *bmp, int cx, int cy, int cw, int ch);
// Copies bitmap data.
// dx/dy = dest co-ordinates
// sx/sy = source co-ordinates
// w/h = width/height
//
// RGBAdest = RGBAsrc
// Clips, does not blend.
void tigrBlit(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h);
// Same as tigrBlit, but alpha blends the source bitmap with the
// target using per pixel alpha and the specified global alpha.
//
// Ablend = Asrc * alpha
// RGBdest = RGBsrc * Ablend + RGBdest * (1 - Ablend)
//
// Blit mode == TIGR_KEEP_ALPHA:
// Adest = Adest
//
// Blit mode == TIGR_BLEND_ALPHA:
// Adest = Asrc * Ablend + Adest * (1 - Ablend)
// Clips and blends.
void tigrBlitAlpha(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, float alpha);
// Same as tigrBlit, but tints the source bitmap with a color
// and alpha blends the resulting source with the destination.
//
// Rblend = Rsrc * Rtint
// Gblend = Gsrc * Gtint
// Bblend = Bsrc * Btint
// Ablend = Asrc * Atint
//
// RGBdest = RGBblend * Ablend + RGBdest * (1 - Ablend)
//
// Blit mode == TIGR_KEEP_ALPHA:
// Adest = Adest
//
// Blit mode == TIGR_BLEND_ALPHA:
// Adest = Ablend * Ablend + Adest * (1 - Ablend)
// Clips and blends.
void tigrBlitTint(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, TPixel tint);
enum TIGRBlitMode {
TIGR_KEEP_ALPHA = 0, // Keep destination alpha value
TIGR_BLEND_ALPHA = 1, // Blend destination alpha (default)
};
// Set destination bitmap blend mode for blit operations.
void tigrBlitMode(Tigr *dest, int mode);
// Helper for making colors.
TIGR_INLINE TPixel tigrRGB(unsigned char r, unsigned char g, unsigned char b)
{
TPixel p; p.r = r; p.g = g; p.b = b; p.a = 0xff; return p;
}
// Helper for making colors.
TIGR_INLINE TPixel tigrRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
TPixel p; p.r = r; p.g = g; p.b = b; p.a = a; return p;
}
// Font printing ----------------------------------------------------------
typedef struct {
int code, x, y, w, h;
} TigrGlyph;
typedef struct {
Tigr *bitmap;
int numGlyphs;
TigrGlyph *glyphs;
} TigrFont;
typedef enum {
TCP_ASCII = 0,
TCP_1252 = 1252,
TCP_UTF32 = 12001
} TCodepage;
// Loads a font.
//
// Codepages:
//
// TCP_ASCII - Regular 7-bit ASCII
// TCP_1252 - Windows 1252
// TCP_UTF32 - Unicode subset
//
// For ASCII and 1252, the font bitmap should contain all characters
// for the given codepage, excluding the first 32 control codes.
//
// For UTF32 - the font bitmap contains a subset of Unicode characters
// and must be in the format generated by tigrFont for UTF32.
//
TigrFont *tigrLoadFont(Tigr *bitmap, int codepage);
// Frees a font.
void tigrFreeFont(TigrFont *font);
// Prints UTF-8 text onto a bitmap.
// NOTE:
// This uses the target bitmap blit mode.
// See tigrBlitTint for details.
void tigrPrint(Tigr *dest, TigrFont *font, int x, int y, TPixel color, const char *text, ...);
// Returns the width/height of a string.
int tigrTextWidth(TigrFont *font, const char *text);
int tigrTextHeight(TigrFont *font, const char *text);
// The built-in font.
extern TigrFont *tfont;
// User Input -------------------------------------------------------------
// Key scancodes. For letters/numbers, use ASCII ('A'-'Z' and '0'-'9').
typedef enum {
TK_PAD0=128,TK_PAD1,TK_PAD2,TK_PAD3,TK_PAD4,TK_PAD5,TK_PAD6,TK_PAD7,TK_PAD8,TK_PAD9,
TK_PADMUL,TK_PADADD,TK_PADENTER,TK_PADSUB,TK_PADDOT,TK_PADDIV,
TK_F1,TK_F2,TK_F3,TK_F4,TK_F5,TK_F6,TK_F7,TK_F8,TK_F9,TK_F10,TK_F11,TK_F12,
TK_BACKSPACE,TK_TAB,TK_RETURN,TK_SHIFT,TK_CONTROL,TK_ALT,TK_PAUSE,TK_CAPSLOCK,
TK_ESCAPE,TK_SPACE,TK_PAGEUP,TK_PAGEDN,TK_END,TK_HOME,TK_LEFT,TK_UP,TK_RIGHT,TK_DOWN,
TK_INSERT,TK_DELETE,TK_LWIN,TK_RWIN,TK_NUMLOCK,TK_SCROLL,TK_LSHIFT,TK_RSHIFT,
TK_LCONTROL,TK_RCONTROL,TK_LALT,TK_RALT,TK_SEMICOLON,TK_EQUALS,TK_COMMA,TK_MINUS,
TK_DOT,TK_SLASH,TK_BACKTICK,TK_LSQUARE,TK_BACKSLASH,TK_RSQUARE,TK_TICK
} TKey;
// Returns mouse input for a window.
void tigrMouse(Tigr *bmp, int *x, int *y, int *buttons);
typedef struct {
int x;
int y;
} TigrTouchPoint;
// Reads touch input for a window.
// Returns number of touch points read.
int tigrTouch(Tigr *bmp, TigrTouchPoint* points, int maxPoints);
// Reads the keyboard for a window.
// Returns non-zero if a key is pressed/held.
// tigrKeyDown tests for the initial press, tigrKeyHeld repeats each frame.
int tigrKeyDown(Tigr *bmp, int key);
int tigrKeyHeld(Tigr *bmp, int key);
// Reads character input for a window.
// Returns the Unicode value of the last key pressed, or 0 if none.
int tigrReadChar(Tigr *bmp);
// Show / hide virtual keyboard.
// (Only available on iOS / Android)
void tigrShowKeyboard(int show);
// Bitmap I/O -------------------------------------------------------------
// Loads a PNG, from either a file or memory. (fileName is UTF-8)
// On error, returns NULL and sets errno.
Tigr *tigrLoadImage(const char *fileName);
Tigr *tigrLoadImageMem(const void *data, int length);
// Saves a PNG to a file. (fileName is UTF-8)
// On error, returns zero and sets errno.
int tigrSaveImage(const char *fileName, Tigr *bmp);
// Helpers ----------------------------------------------------------------
// Returns the amount of time elapsed since tigrTime was last called,
// or zero on the first call.
float tigrTime(void);
// Displays an error message and quits. (UTF-8)
// 'bmp' can be NULL.
void tigrError(Tigr *bmp, const char *message, ...);
// Reads an entire file into memory. (fileName is UTF-8)
// Free it yourself after with 'free'.
// On error, returns NULL and sets errno.
// TIGR will automatically append a NUL terminator byte
// to the end (not included in the length)
void *tigrReadFile(const char *fileName, int *length);
// Decompresses DEFLATEd zip/zlib data into a buffer.
// Returns non-zero on success.
int tigrInflate(void *out, unsigned outlen, const void *in, unsigned inlen);
// Decodes a single UTF8 codepoint and returns the next pointer.
const char *tigrDecodeUTF8(const char *text, int *cp);
// Encodes a single UTF8 codepoint and returns the next pointer.
char *tigrEncodeUTF8(char *text, int cp);
#ifdef __cplusplus
}
#endif
// TIGR - TIny GRaphics Library - v3.1
// ^^ ^^
//
// rawr.
/*
This is free and unencumbered software released into the public domain.
Our intent is that anyone is free to copy and use this software,
for any purpose, in any form, and by any means.
The authors dedicate any and all copyright interest in the software
to the public domain, at their own expense for the betterment of mankind.
The software is provided "as is", without any kind of warranty, including
any implied warranty. If it breaks, you get to keep both pieces.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Compiler configuration.
#ifdef _MSC_VER
#define TIGR_INLINE static __forceinline
#else
#define TIGR_INLINE static inline
#endif
// Bitmaps ----------------------------------------------------------------
// This struct contains one pixel.
typedef struct {
unsigned char r, g, b, a;
} TPixel;
// Window flags.
#define TIGR_FIXED 0 // window's bitmap is a fixed size (default)
#define TIGR_AUTO 1 // window's bitmap is scaled with the window
#define TIGR_2X 2 // always enforce (at least) 2X pixel scale
#define TIGR_3X 4 // always enforce (at least) 3X pixel scale
#define TIGR_4X 8 // always enforce (at least) 4X pixel scale
#define TIGR_RETINA 16 // enable retina support on OS X
#define TIGR_NOCURSOR 32 // hide cursor
#define TIGR_FULLSCREEN 64 // start in full-screen mode
// A Tigr bitmap.
typedef struct Tigr {
int w, h; // width/height (unscaled)
int cx, cy, cw, ch; // clip rect
TPixel *pix; // pixel data
void *handle; // OS window handle, NULL for off-screen bitmaps.
int blitMode; // Target bitmap blit mode
} Tigr;
// Creates a new empty window with a given bitmap size.
//
// Title is UTF-8.
//
// In TIGR_FIXED mode, the window is made as large as possible to contain an integer-scaled
// version of the bitmap while still fitting on the screen. Resizing the window will adapt
// the scale in integer steps to fit the bitmap.
//
// In TIGR_AUTO mode, the initial window size is set to the bitmap size times the pixel
// scale. Resizing the window will resize the bitmap using the specified scale.
// For example, in forced 2X mode, the window will be twice as wide (and high) as the bitmap.
//
// Turning on TIGR_RETINA mode will request full backing resolution on OSX, meaning that
// the effective window size might be integer scaled to a larger size. In TIGR_AUTO mode,
// this means that the Tigr bitmap will change size if the window is moved between
// retina and non-retina screens.
//
Tigr *tigrWindow(int w, int h, const char *title, int flags);
// Creates an empty off-screen bitmap.
Tigr *tigrBitmap(int w, int h);
// Deletes a window/bitmap.
void tigrFree(Tigr *bmp);
// Returns non-zero if the user requested to close a window.
int tigrClosed(Tigr *bmp);
// Displays a window's contents on-screen and updates input.
void tigrUpdate(Tigr *bmp);
// Called before doing direct OpenGL calls and before tigrUpdate.
// Returns non-zero if OpenGL is available.
int tigrBeginOpenGL(Tigr *bmp);
// Sets post shader for a window.
// This replaces the built-in post-FX shader.
void tigrSetPostShader(Tigr *bmp, const char* code, int size);
// Sets post-FX properties for a window.
//
// The built-in post-FX shader uses the following parameters:
// p1: hblur - use bilinear filtering along the x-axis (pixels)
// p2: vblur - use bilinear filtering along the y-axis (pixels)
// p3: scanlines - CRT scanlines effect (0-1)
// p4: contrast - contrast boost (1 = no change, 2 = 2X contrast, etc)
void tigrSetPostFX(Tigr *bmp, float p1, float p2, float p3, float p4);
// Drawing ----------------------------------------------------------------
// Helper for reading pixels.
// For high performance, just access bmp->pix directly.
TPixel tigrGet(Tigr *bmp, int x, int y);
// Plots a pixel.
// Clips and blends.
// For high performance, just access bmp->pix directly.
void tigrPlot(Tigr *bmp, int x, int y, TPixel pix);
// Clears a bitmap to a color.
// No blending, no clipping.
void tigrClear(Tigr *bmp, TPixel color);
// Fills a rectangular area.
// No blending, no clipping.
void tigrFill(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Draws a line.
// Start pixel is drawn, end pixel is not.
// Clips and blends.
void tigrLine(Tigr *bmp, int x0, int y0, int x1, int y1, TPixel color);
// Draws an empty rectangle.
// Drawing a 1x1 rectangle yields the same result as calling tigrPlot.
// Clips and blends.
void tigrRect(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Fills a rectangle.
// Fills the inside of the specified rectangular area.
// Calling tigrRect followed by tigrFillRect using the same arguments
// causes no overdrawing.
// Clips and blends.
void tigrFillRect(Tigr *bmp, int x, int y, int w, int h, TPixel color);
// Draws a circle.
// Drawing a zero radius circle yields the same result as calling tigrPlot.
// Drawing a circle with radius one draws a circle three pixels wide.
// Clips and blends.
void tigrCircle(Tigr *bmp, int x, int y, int r, TPixel color);
// Fills a circle.
// Fills the inside of the specified circle.
// Calling tigrCircle followed by tigrFillCircle using the same arguments
// causes no overdrawing.
// Filling a circle with zero radius has no effect.
// Clips and blends.
void tigrFillCircle(Tigr *bmp, int x, int y, int r, TPixel color);
// Sets clip rect.
// Set to (0, 0, -1, -1) to reset clipping to full bitmap.
void tigrClip(Tigr *bmp, int cx, int cy, int cw, int ch);
// Copies bitmap data.
// dx/dy = dest co-ordinates
// sx/sy = source co-ordinates
// w/h = width/height
//
// RGBAdest = RGBAsrc
// Clips, does not blend.
void tigrBlit(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h);
// Same as tigrBlit, but alpha blends the source bitmap with the
// target using per pixel alpha and the specified global alpha.
//
// Ablend = Asrc * alpha
// RGBdest = RGBsrc * Ablend + RGBdest * (1 - Ablend)
//
// Blit mode == TIGR_KEEP_ALPHA:
// Adest = Adest
//
// Blit mode == TIGR_BLEND_ALPHA:
// Adest = Asrc * Ablend + Adest * (1 - Ablend)
// Clips and blends.
void tigrBlitAlpha(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, float alpha);
// Same as tigrBlit, but tints the source bitmap with a color
// and alpha blends the resulting source with the destination.
//
// Rblend = Rsrc * Rtint
// Gblend = Gsrc * Gtint
// Bblend = Bsrc * Btint
// Ablend = Asrc * Atint
//
// RGBdest = RGBblend * Ablend + RGBdest * (1 - Ablend)
//
// Blit mode == TIGR_KEEP_ALPHA:
// Adest = Adest
//
// Blit mode == TIGR_BLEND_ALPHA:
// Adest = Ablend * Ablend + Adest * (1 - Ablend)
// Clips and blends.
void tigrBlitTint(Tigr *dest, Tigr *src, int dx, int dy, int sx, int sy, int w, int h, TPixel tint);
enum TIGRBlitMode {
TIGR_KEEP_ALPHA = 0, // Keep destination alpha value
TIGR_BLEND_ALPHA = 1, // Blend destination alpha (default)
};
// Set destination bitmap blend mode for blit operations.
void tigrBlitMode(Tigr *dest, int mode);
// Helper for making colors.
TIGR_INLINE TPixel tigrRGB(unsigned char r, unsigned char g, unsigned char b)
{
TPixel p; p.r = r; p.g = g; p.b = b; p.a = 0xff; return p;
}
// Helper for making colors.
TIGR_INLINE TPixel tigrRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
TPixel p; p.r = r; p.g = g; p.b = b; p.a = a; return p;
}
// Font printing ----------------------------------------------------------
typedef struct {
int code, x, y, w, h;
} TigrGlyph;
typedef struct {
Tigr *bitmap;
int numGlyphs;
TigrGlyph *glyphs;
} TigrFont;
typedef enum {
TCP_ASCII = 0,
TCP_1252 = 1252,
TCP_UTF32 = 12001
} TCodepage;
// Loads a font.
//
// Codepages:
//
// TCP_ASCII - Regular 7-bit ASCII
// TCP_1252 - Windows 1252
// TCP_UTF32 - Unicode subset
//
// For ASCII and 1252, the font bitmap should contain all characters
// for the given codepage, excluding the first 32 control codes.
//
// For UTF32 - the font bitmap contains a subset of Unicode characters
// and must be in the format generated by tigrFont for UTF32.
//
TigrFont *tigrLoadFont(Tigr *bitmap, int codepage);
// Frees a font.
void tigrFreeFont(TigrFont *font);
// Prints UTF-8 text onto a bitmap.
// NOTE:
// This uses the target bitmap blit mode.
// See tigrBlitTint for details.
void tigrPrint(Tigr *dest, TigrFont *font, int x, int y, TPixel color, const char *text, ...);
// Returns the width/height of a string.
int tigrTextWidth(TigrFont *font, const char *text);
int tigrTextHeight(TigrFont *font, const char *text);
// The built-in font.
extern TigrFont *tfont;
// User Input -------------------------------------------------------------
// Key scancodes. For letters/numbers, use ASCII ('A'-'Z' and '0'-'9').
typedef enum {
TK_PAD0=128,TK_PAD1,TK_PAD2,TK_PAD3,TK_PAD4,TK_PAD5,TK_PAD6,TK_PAD7,TK_PAD8,TK_PAD9,
TK_PADMUL,TK_PADADD,TK_PADENTER,TK_PADSUB,TK_PADDOT,TK_PADDIV,
TK_F1,TK_F2,TK_F3,TK_F4,TK_F5,TK_F6,TK_F7,TK_F8,TK_F9,TK_F10,TK_F11,TK_F12,
TK_BACKSPACE,TK_TAB,TK_RETURN,TK_SHIFT,TK_CONTROL,TK_ALT,TK_PAUSE,TK_CAPSLOCK,
TK_ESCAPE,TK_SPACE,TK_PAGEUP,TK_PAGEDN,TK_END,TK_HOME,TK_LEFT,TK_UP,TK_RIGHT,TK_DOWN,
TK_INSERT,TK_DELETE,TK_LWIN,TK_RWIN,TK_NUMLOCK,TK_SCROLL,TK_LSHIFT,TK_RSHIFT,
TK_LCONTROL,TK_RCONTROL,TK_LALT,TK_RALT,TK_SEMICOLON,TK_EQUALS,TK_COMMA,TK_MINUS,
TK_DOT,TK_SLASH,TK_BACKTICK,TK_LSQUARE,TK_BACKSLASH,TK_RSQUARE,TK_TICK
} TKey;
// Returns mouse input for a window.
void tigrMouse(Tigr *bmp, int *x, int *y, int *buttons);
typedef struct {
int x;
int y;
} TigrTouchPoint;
// Reads touch input for a window.
// Returns number of touch points read.
int tigrTouch(Tigr *bmp, TigrTouchPoint* points, int maxPoints);
// Reads the keyboard for a window.
// Returns non-zero if a key is pressed/held.
// tigrKeyDown tests for the initial press, tigrKeyHeld repeats each frame.
int tigrKeyDown(Tigr *bmp, int key);
int tigrKeyHeld(Tigr *bmp, int key);
// Reads character input for a window.
// Returns the Unicode value of the last key pressed, or 0 if none.
int tigrReadChar(Tigr *bmp);
// Show / hide virtual keyboard.
// (Only available on iOS / Android)
void tigrShowKeyboard(int show);
// Bitmap I/O -------------------------------------------------------------
// Loads a PNG, from either a file or memory. (fileName is UTF-8)
// On error, returns NULL and sets errno.
Tigr *tigrLoadImage(const char *fileName);
Tigr *tigrLoadImageMem(const void *data, int length);
// Saves a PNG to a file. (fileName is UTF-8)
// On error, returns zero and sets errno.
int tigrSaveImage(const char *fileName, Tigr *bmp);
// Helpers ----------------------------------------------------------------
// Returns the amount of time elapsed since tigrTime was last called,
// or zero on the first call.
float tigrTime(void);
// Displays an error message and quits. (UTF-8)
// 'bmp' can be NULL.
void tigrError(Tigr *bmp, const char *message, ...);
// Reads an entire file into memory. (fileName is UTF-8)
// Free it yourself after with 'free'.
// On error, returns NULL and sets errno.
// TIGR will automatically append a NUL terminator byte
// to the end (not included in the length)
void *tigrReadFile(const char *fileName, int *length);
// Decompresses DEFLATEd zip/zlib data into a buffer.
// Returns non-zero on success.
int tigrInflate(void *out, unsigned outlen, const void *in, unsigned inlen);
// Decodes a single UTF8 codepoint and returns the next pointer.
const char *tigrDecodeUTF8(const char *text, int *cp);
// Encodes a single UTF8 codepoint and returns the next pointer.
char *tigrEncodeUTF8(char *text, int cp);
#ifdef __cplusplus
}
#endif