Gb, Cpu, Ppu modules, general refactoring
This commit is contained in:
parent
53d1e6904c
commit
b2a1b5909f
66
Makefile
66
Makefile
|
@ -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
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
24
cpu.h
24
cpu.h
|
@ -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
88
gb.c
Normal 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
22
gb.h
Normal 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
127
main.c
|
@ -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
108
ppu.c
|
@ -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
23
ppu.h
|
@ -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);
|
||||
|
|
712
tigr/tigr.h
712
tigr/tigr.h
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user