psp gfx scaling/etc stuff

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@279 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2007-10-25 19:39:40 +00:00
parent 3aa1e148a2
commit 8ab3e3c1cf
26 changed files with 567 additions and 321 deletions

View file

@ -11,9 +11,9 @@ amalgamate = 0
CFLAGS += -I../.. -I. -D_UNZIP_SUPPORT -DNO_SYNC # -DBENCHMARK
CFLAGS += -Wall -Winline
CFLAGS += -Wall -Winline -G0
ifeq ($(DEBUG),)
CFLAGS += -O2 -G0 -ftracer -fstrength-reduce -ffast-math
CFLAGS += -O2 -ftracer -fstrength-reduce -ffast-math
else
CFLAGS += -ggdb
endif
@ -52,7 +52,8 @@ OBJS += ../../Pico/sound/mix.o
OBJS += ../../Pico/sound/sn76496.o ../../Pico/sound/ym2612.o
# zlib (hacked)
OBJS += ../../zlib/gzio.o ../../zlib/inffast.o ../../zlib/inflate.o ../../zlib/inftrees.o ../../zlib/trees.o \
../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o
../../zlib/deflate.o ../../zlib/crc32.o ../../zlib/adler32.o ../../zlib/zutil.o ../../zlib/compress.o \
../../zlib/uncompr.o
# unzip
OBJS += ../../unzip/unzip.o ../../unzip/unzip_stream.o
# CPU cores
@ -70,6 +71,8 @@ OBJS += ../../cpu/mz80/mz80.o
else
$(error nothing here!)
endif
# bg images
OBJS += data/bg32.o data/bg40.o
LIBS += -lpng -lm -lpspgu -lpsppower -Wl,-Map=PicoDrive.map # -lpspaudio -lpsphprm
@ -109,7 +112,13 @@ readme.txt: ../../tools/textfilter ../base_readme.txt
@echo ">>>" $<
$(CC) $(CFLAGS) -Wno-unused -c $< -o $@
# ?
data/bg32.o: data/bg32.bin
bin2o -i $< $@ bgdatac32
data/bg40.o: data/bg40.bin
bin2o -i $< $@ bgdatac40
#
up: EBOOT.PBP
@cp -v $^ /media/disk/PSP/GAME/PicoDrive/

BIN
platform/psp/data/bg32.bin Normal file

Binary file not shown.

BIN
platform/psp/data/bg40.bin Normal file

Binary file not shown.

View file

@ -15,9 +15,9 @@
#include "../../Pico/PicoInt.h"
#ifdef BENCHMARK
#define OSD_FPS_X 220
#define OSD_FPS_X 380
#else
#define OSD_FPS_X 260
#define OSD_FPS_X 420
#endif
char romFileName[PATH_MAX];
@ -29,7 +29,7 @@ static unsigned int noticeMsgTime = 0;
int reset_timing = 0; // do we need this?
static void blit(const char *fps, const char *notice);
static void blit2(const char *fps, const char *notice);
static void clearArea(int full);
void emu_noticeMsgUpdated(void)
@ -42,24 +42,31 @@ void emu_getMainDir(char *dst, int len)
if (len > 0) *dst = 0;
}
static void emu_msg_cb(const char *msg)
static void osd_text(int x, const char *text, int is_active)
{
void *fb = psp_video_get_active_fb();
unsigned short *screen = is_active ? psp_video_get_active_fb() : psp_screen;
int len = strlen(text) * 8 / 2;
int *p, h;
void *tmp;
for (h = 0; h < 8; h++) {
p = (int *) (screen+x+512*(264+h));
p = (int *) ((int)p & ~3); // align
memset32(p, 0, len);
}
if (is_active) { tmp = psp_screen; psp_screen = screen; } // nasty pointer tricks
emu_textOut16(x, 264, text);
if (is_active) psp_screen = tmp;
}
memset32((int *)((char *)fb + 512*264*2), 0, 512*8*2/4);
emu_textOut16(4, 264, msg);
void emu_msg_cb(const char *msg)
{
osd_text(4, msg, 1);
noticeMsgTime = sceKernelGetSystemTimeLow() - 2000000;
/* assumption: emu_msg_cb gets called only when something slow is about to happen */
reset_timing = 1;
}
void emu_stateCb(const char *str)
{
clearArea(0);
blit("", str);
}
static void emu_msg_tray_open(void)
{
strcpy(noticeMsg, "CD tray opened");
@ -126,15 +133,15 @@ void emu_setDefaultConfig(void)
currentConfig.KeyBinds[13] = 1<<5;
currentConfig.KeyBinds[15] = 1<<6;
currentConfig.KeyBinds[ 3] = 1<<7;
currentConfig.KeyBinds[23] = 1<<26; // switch rend
currentConfig.KeyBinds[ 8] = 1<<27; // save state
currentConfig.KeyBinds[ 9] = 1<<28; // load state
currentConfig.PicoCDBuffers = 0;
currentConfig.scaling = 0;
currentConfig.scaling = 1; // bilinear filtering for psp
currentConfig.scale = currentConfig.hscale32 = currentConfig.hscale40 = 1.0;
}
static unsigned short __attribute__((aligned(16))) localPal[0x100];
extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
struct Vertex
{
@ -142,132 +149,203 @@ struct Vertex
short x,y,z;
};
static struct Vertex __attribute__((aligned(4))) g_vertices[2];
static unsigned short __attribute__((aligned(16))) localPal[0x100];
static int dynamic_palette = 0, need_pal_upload = 0, blit_16bit_mode = 0;
static int fbimg_offs = 0;
static void set_scaling_params(void)
{
int src_width, fbimg_width, fbimg_height, fbimg_xoffs, fbimg_yoffs;
g_vertices[0].x = g_vertices[0].y =
g_vertices[0].z = g_vertices[1].z = 0;
fbimg_height = (int)(240.0 * currentConfig.scale + 0.5);
if (Pico.video.reg[12] & 1) {
fbimg_width = (int)(320.0 * currentConfig.scale * currentConfig.hscale40 + 0.5);
src_width = 320;
} else {
fbimg_width = (int)(256.0 * currentConfig.scale * currentConfig.hscale32 + 0.5);
src_width = 256;
}
if (fbimg_width >= 480) {
g_vertices[0].u = (fbimg_width-480)/2;
g_vertices[1].u = src_width - (fbimg_width-480)/2;
fbimg_width = 480;
fbimg_xoffs = 0;
} else {
g_vertices[0].u = 0;
g_vertices[1].u = src_width;
fbimg_xoffs = 240 - fbimg_width/2;
}
if (fbimg_height >= 272) {
g_vertices[0].v = (fbimg_height-272)/2;
g_vertices[1].v = 240 - (fbimg_height-272)/2;
fbimg_height = 272;
fbimg_yoffs = 0;
} else {
g_vertices[0].v = 0;
g_vertices[1].v = 240;
fbimg_yoffs = 136 - fbimg_height/2;
}
g_vertices[1].x = fbimg_width;
g_vertices[1].y = fbimg_height;
if (fbimg_xoffs < 0) fbimg_xoffs = 0;
if (fbimg_yoffs < 0) fbimg_yoffs = 0;
fbimg_offs = (fbimg_yoffs*512 + fbimg_xoffs) * 2; // dst is always 16bit
lprintf("set_scaling_params:\n");
lprintf("offs: %i, %i\n", fbimg_xoffs, fbimg_yoffs);
lprintf("xy0, xy1: %i, %i; %i, %i\n", g_vertices[0].x, g_vertices[0].y, g_vertices[1].x, g_vertices[1].y);
lprintf("uv0, uv1: %i, %i; %i, %i\n", g_vertices[0].u, g_vertices[0].v, g_vertices[1].u, g_vertices[1].v);
}
static void do_slowmode_pal(void)
{
unsigned int *spal=(void *)Pico.cram;
unsigned int *dpal=(void *)localPal;
int i;
for (i = 0x3f/2; i >= 0; i--)
dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
if (Pico.video.reg[0xC]&8) // shadow/hilight?
{
// shadowed pixels
for (i = 0x3f/2; i >= 0; i--)
dpal[0x20|i] = dpal[0x60|i] = (spal[i]>>1)&0x738e738e;
// hilighted pixels
for (i = 0x3f; i >= 0; i--) {
int t=localPal[i]&0xe71c;t+=0x4208;
if (t&0x20) t|=0x1c;
if (t&0x800) t|=0x700;
if (t&0x10000) t|=0xe000;
t&=0xe71c;
localPal[0x80|i]=(unsigned short)t;
}
localPal[0xe0] = 0;
}
Pico.m.dirtyPal = 0;
need_pal_upload = 1;
}
static void do_slowmode_lines(int line_to)
{
int line = 0, line_len = (Pico.video.reg[12]&1) ? 320 : 256;
unsigned short *dst = (unsigned short *)VRAM_STUFF + 512*240/2;
unsigned char *src = (unsigned char *)VRAM_CACHED_STUFF + 16;
if (!(Pico.video.reg[1]&8)) { line = 8; dst += 512*8; src += 512*8; }
for (; line < line_to; line++, dst+=512, src+=512)
amips_clut(dst, src, localPal, line_len);
}
static void EmuScanPrepare(void)
{
HighCol = VRAM_STUFF;
HighCol = (unsigned char *)VRAM_CACHED_STUFF + 8;
if (!(Pico.video.reg[1]&8)) HighCol += 8*512;
#if 0
sceGuSync(0,0); // sync with prev
sceGuStart(GU_DIRECT, guCmdList);
// sceGuDispBuffer(480, 272, psp_screen == VRAM_FB0 ? VRAMOFFS_FB1 : VRAMOFFS_FB0, 512);
sceGuDrawBuffer(GU_PSM_5650, psp_screen == VRAM_FB0 ? VRAMOFFS_FB0 : VRAMOFFS_FB1, 512); // point to back fb?
sceGuFinish();
#endif
dynamic_palette = 0;
if (Pico.m.dirtyPal)
do_slowmode_pal();
}
static int EmuScan16(unsigned int num, void *sdata)
static int EmuScanSlow(unsigned int num, void *sdata)
{
// struct Vertex* vertices;
if (!(Pico.video.reg[1]&8)) num += 8;
//DrawLineDest = (unsigned short *) psp_screen + 512*(num+1);
HighCol = (unsigned char *)psp_screen + num*512;
#if 0
sceGuSync(0,0); // sync with prev
sceGuStart(GU_DIRECT, guCmdList);
if (Pico.m.dirtyPal) {
int i, *dpal = (void *)localPal, *spal = (int *)Pico.cram;
Pico.m.dirtyPal = 0;
for (i = 0x3f/2; i >= 0; i--)
dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
if (!dynamic_palette) {
do_slowmode_lines(num);
dynamic_palette = 1;
}
do_slowmode_pal();
}
// setup CLUT texture
if (dynamic_palette) {
int line_len = (Pico.video.reg[12]&1) ? 320 : 256;
void *dst = (char *)VRAM_STUFF + 512*240 + 512*2*num;
amips_clut(dst, HighCol + 8, localPal, line_len);
} else
HighCol = (unsigned char *)VRAM_CACHED_STUFF + (num+1)*512 + 8;
// sceGuClutMode(GU_PSM_5650,0,0xff,0);
// sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
// sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
// sceGuTexImage(0,512,1/*512*/,512,VRAM_STUFF);
// sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
// sceGuTexFilter(GU_LINEAR,GU_LINEAR);
// sceGuTexScale(1.0f,1.0f);
// sceGuTexOffset(0.0f,0.0f);
// sceGuAmbientColor(0xffffffff);
// render sprite
// sceGuColor(0xffffffff);
vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
vertices[0].u = 0; vertices[0].v = 0;
vertices[0].x = 0; vertices[0].y = num; vertices[0].z = 0;
vertices[1].u = 320; vertices[1].v = 512;
vertices[1].x = 320; vertices[1].y = num+1; vertices[1].z = 0;
//sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
sceGuFinish();
#endif
return 0;
}
static void draw2_clut(void)
static void blitscreen_clut(void)
{
struct Vertex* vertices;
int x;
int offs = fbimg_offs;
offs += (psp_screen == VRAM_FB0) ? VRAMOFFS_FB0 : VRAMOFFS_FB1;
sceKernelDcacheWritebackAll(); // for PicoDraw2FB
sceKernelDcacheWritebackAll();
sceGuSync(0,0); // sync with prev
sceGuStart(GU_DIRECT, guCmdList);
// sceGuDispBuffer(480, 272, psp_screen == VRAM_FB0 ? VRAMOFFS_FB1 : VRAMOFFS_FB0, 512);
sceGuDrawBuffer(GU_PSM_5650, psp_screen == VRAM_FB0 ? VRAMOFFS_FB0 : VRAMOFFS_FB1, 512); // point to back fb?
sceGuDrawBuffer(GU_PSM_5650, (void *)offs, 512); // point to back buffer
if (Pico.m.dirtyPal) {
int i, *dpal = (void *)localPal, *spal = (int *)Pico.cram;
Pico.m.dirtyPal = 0;
for (i = 0x3f/2; i >= 0; i--)
dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
}
#define SLICE_WIDTH 32
for (x = 0; x < 320; x += SLICE_WIDTH)
if (dynamic_palette)
{
// render sprite
vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
vertices[0].u = vertices[0].x = x;
vertices[0].v = vertices[0].y = 0;
vertices[0].z = 0;
vertices[1].u = vertices[1].x = x + SLICE_WIDTH;
vertices[1].v = vertices[1].y = 224;
vertices[1].z = 0;
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
if (!blit_16bit_mode) {
sceGuTexMode(GU_PSM_5650, 0, 0, 0);
sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 512*240);
blit_16bit_mode = 1;
}
}
else
{
if (blit_16bit_mode) {
sceGuClutMode(GU_PSM_5650,0,0xff,0);
sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 16);
blit_16bit_mode = 0;
}
if ((PicoOpt&0x10) && Pico.m.dirtyPal)
{
int i, *dpal = (void *)localPal, *spal = (int *)Pico.cram;
for (i = 0x3f/2; i >= 0; i--)
dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
localPal[0xe0] = 0;
Pico.m.dirtyPal = 0;
need_pal_upload = 1;
}
if (need_pal_upload) {
need_pal_upload = 0;
sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
}
}
#if 1
if (g_vertices[0].u == 0 && g_vertices[1].u == g_vertices[1].x)
{
struct Vertex* vertices;
int x;
#define SLICE_WIDTH 32
for (x = 0; x < g_vertices[1].x; x += SLICE_WIDTH)
{
// render sprite
vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
memcpy(vertices, g_vertices, 2 * sizeof(struct Vertex));
vertices[0].u = vertices[0].x = x;
vertices[1].u = vertices[1].x = x + SLICE_WIDTH;
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
}
// lprintf("listlen: %iB\n", sceGuCheckList()); // ~480 only
}
else
#endif
sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,g_vertices);
sceGuFinish();
}
static int EmuScan8(unsigned int num, void *sdata)
{
// draw like the fast renderer
// TODO?
//if (!(Pico.video.reg[1]&8)) num += 8;
//HighCol = gfx_buffer + 328*(num+1);
return 0;
}
static void osd_text(int x, const char *text)
{
int len = strlen(text) * 8 / 2;
int *p, h;
for (h = 0; h < 8; h++) {
p = (int *) ((unsigned short *) psp_screen+x+512*(264+h));
p = (int *) ((int)p & ~3); // align
memset32(p, 0, len);
}
emu_textOut16(x, 264, text);
}
static void cd_leds(void)
{
static int old_reg = 0;
@ -285,75 +363,56 @@ static void cd_leds(void)
}
static void blit(const char *fps, const char *notice)
static void dbg_text(void)
{
int *p, h, len;
char text[128];
sprintf(text, "sl: %i, 16b: %i", g_vertices[0].u == 0 && g_vertices[1].u == g_vertices[1].x, blit_16bit_mode);
len = strlen(text) * 8 / 2;
for (h = 0; h < 8; h++) {
p = (int *) ((unsigned short *) psp_screen+2+512*(256+h));
p = (int *) ((int)p & ~3); // align
memset32(p, 0, len);
}
emu_textOut16(2, 256, text);
}
/* called after rendering is done, but frame emulation is not finished */
void blit1(void)
{
if (PicoOpt&0x10)
{
int i;
unsigned char *pd;
// clear top and bottom trash
for (pd = PicoDraw2FB+8, i = 8; i > 0; i--, pd += 512)
memset32((int *)pd, 0xe0e0e0e0, 320/4);
for (pd = PicoDraw2FB+512*232+8, i = 8; i > 0; i--, pd += 512)
memset32((int *)pd, 0xe0e0e0e0, 320/4);
}
blitscreen_clut();
}
static void blit2(const char *fps, const char *notice)
{
int emu_opt = currentConfig.EmuOpt;
if (PicoOpt&0x10)
{
#if 1
draw2_clut();
#else
extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
int i; // , lines_flags = 224;
unsigned short *pd = psp_screen;
unsigned char *ps = PicoDraw2FB+328*8+8;
// 8bit fast renderer
if (Pico.m.dirtyPal) {
int *dpal = (void *)localPal;
int *spal = (int *)Pico.cram;
Pico.m.dirtyPal = 0;
for (i = 0x3f/2; i >= 0; i--)
dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
}
// if (!(Pico.video.reg[12]&1)) lines_flags|=0x10000;
// if (currentConfig.EmuOpt&0x4000)
// lines_flags|=0x40000; // (Pico.m.frame_count&1)?0x20000:0x40000;
//vidCpy8to16((unsigned short *)giz_screen+321*8, PicoDraw2FB+328*8, localPal, lines_flags);
for (i = 224; i > 0; i--, pd+=512, ps+=328)
amips_clut(pd, ps, localPal, 320);
#endif
}
#if 0
else if (!(emu_opt&0x80))
{
int lines_flags;
// 8bit accurate renderer
if (Pico.m.dirtyPal) {
Pico.m.dirtyPal = 0;
vidConvCpyRGB565(localPal, Pico.cram, 0x40);
if (Pico.video.reg[0xC]&8) { // shadow/hilight mode
//vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40);
//vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40); // TODO?
blockcpy(localPal+0xc0, localPal+0x40, 0x40*2);
localPal[0xc0] = 0x0600;
localPal[0xd0] = 0xc000;
localPal[0xe0] = 0x0000; // reserved pixels for OSD
localPal[0xf0] = 0xffff;
}
/* no support
else if (rendstatus & 0x20) { // mid-frame palette changes
vidConvCpyRGB565(localPal+0x40, HighPal, 0x40);
vidConvCpyRGB565(localPal+0x80, HighPal+0x40, 0x40);
} */
}
lines_flags = (Pico.video.reg[1]&8) ? 240 : 224;
if (!(Pico.video.reg[12]&1)) lines_flags|=0x10000;
if (currentConfig.EmuOpt&0x4000)
lines_flags|=0x40000; // (Pico.m.frame_count&1)?0x20000:0x40000;
vidCpy8to16((unsigned short *)giz_screen+321*8, PicoDraw2FB+328*8, localPal, lines_flags);
}
#endif
sceGuSync(0,0);
if (notice || (emu_opt & 2)) {
if (notice) osd_text(4, notice);
if (emu_opt & 2) osd_text(OSD_FPS_X, fps);
if (notice) osd_text(4, notice, 0);
if (emu_opt & 2) osd_text(OSD_FPS_X, fps, 0);
}
dbg_text();
if ((emu_opt & 0x400) && (PicoMCD & 1))
cd_leds();
sceGuSync(0,0);
psp_video_flip(0);
}
@ -364,6 +423,8 @@ static void clearArea(int full)
memset32(psp_screen, 0, 512*272*2/4);
psp_video_flip(0);
memset32(psp_screen, 0, 512*272*2/4);
memset32(VRAM_CACHED_STUFF, 0xe0e0e0e0, 512*240/4);
memset32((int *)VRAM_CACHED_STUFF+512*240/4, 0, 512*240*2/4);
} else {
void *fb = psp_video_get_active_fb();
memset32((int *)((char *)psp_screen + 512*264*2), 0, 512*8*2/4);
@ -378,43 +439,29 @@ static void vidResetMode(void)
sceGuStart(GU_DIRECT, guCmdList);
sceGuClutMode(GU_PSM_5650,0,0xff,0);
//sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
if (currentConfig.scaling)
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
else sceGuTexFilter(GU_NEAREST, GU_NEAREST);
sceGuTexScale(1.0f,1.0f);
sceGuTexOffset(0.0f,0.0f);
sceGuAmbientColor(0xffffffff);
sceGuColor(0xffffffff);
sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 16);
if (PicoOpt&0x10) {
sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 8*512+16);
// slow rend.
PicoDrawSetColorFormat(-1);
PicoScan = EmuScanSlow;
} else if (currentConfig.EmuOpt&0x80) {
PicoDrawSetColorFormat(/*1*/-1);
PicoScan = EmuScan16;
sceGuTexImage(0,512,1/*512*/,512,VRAM_STUFF);
} else {
PicoDrawSetColorFormat(-1);
PicoScan = EmuScan8;
}
if ((PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80)) {
// setup pal for 8-bit modes
localPal[0xc0] = 0x0600;
localPal[0xd0] = 0xc000;
localPal[0xe0] = 0x0000; // reserved pixels for OSD
localPal[0xf0] = 0xffff;
}
localPal[0xe0] = 0;
Pico.m.dirtyPal = 1;
blit_16bit_mode = dynamic_palette = 0;
sceGuFinish();
set_scaling_params();
sceGuSync(0,0);
clearArea(1);
}
/*
static void updateSound(int len)
{
@ -440,11 +487,16 @@ void emu_forcedFrame(void)
PicoOpt |= 0x4080; // soft_scale | acc_sprites
currentConfig.EmuOpt |= 0x80;
PicoDrawSetColorFormat(1);
PicoScan = EmuScan16;
vidResetMode();
memset32(VRAM_CACHED_STUFF, 0xe0e0e0e0, 512*8/4); // borders
memset32((int *)VRAM_CACHED_STUFF + 512*232/4, 0xe0e0e0e0, 512*8/4);
PicoDrawSetColorFormat(-1);
PicoScan = EmuScanSlow;
EmuScanPrepare();
Pico.m.dirtyPal = 1;
PicoFrameDrawOnly();
blit1();
sceGuSync(0,0);
PicoOpt = po_old;
currentConfig.EmuOpt = eo_old;
@ -462,7 +514,7 @@ static void RunEvents(unsigned int which)
(!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) // save
{
int keys;
blit("", (which & 0x1000) ? "LOAD STATE? (X=yes, O=no)" : "OVERWRITE SAVE? (X=yes, O=no)");
blit2("", (which & 0x1000) ? "LOAD STATE? (X=yes, O=no)" : "OVERWRITE SAVE? (X=yes, O=no)");
while( !((keys = psp_pad_read(1)) & (BTN_X|BTN_CIRCLE)) )
psp_msleep(50);
if (keys & BTN_CIRCLE) do_it = 0;
@ -473,8 +525,8 @@ static void RunEvents(unsigned int which)
if (do_it)
{
osd_text(4, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME");
PicoStateProgressCB = emu_stateCb;
osd_text(4, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME", 1);
PicoStateProgressCB = emu_msg_cb;
emu_SaveLoadGame((which & 0x1000) >> 12, 0);
PicoStateProgressCB = NULL;
psp_msleep(0);
@ -644,6 +696,7 @@ void emu_Loop(void)
// make sure we are in correct mode
vidResetMode();
clearArea(1);
Pico.m.dirtyPal = 1;
oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
find_combos();
@ -721,6 +774,7 @@ void emu_Loop(void)
if (modes != oldmodes) {
oldmodes = modes;
clearArea(1);
set_scaling_params();
}
// second passed?
@ -798,7 +852,7 @@ void emu_Loop(void)
PicoFrame();
blit(fpsbuff, notice);
blit2(fpsbuff, notice);
// check time
tval = sceKernelGetSystemTimeLow();
@ -829,7 +883,7 @@ void emu_Loop(void)
*/
// save SRAM
if ((currentConfig.EmuOpt & 1) && SRam.changed) {
emu_stateCb("Writing SRAM/BRAM..");
emu_msg_cb("Writing SRAM/BRAM..");
emu_SaveLoadGame(0, 1);
SRam.changed = 0;
}

View file

@ -26,6 +26,6 @@ void emu_Loop(void);
void emu_ResetGame(void);
void emu_forcedFrame(void);
void emu_stateCb(const char *str);
void emu_msg_cb(const char *msg);

View file

@ -6,7 +6,6 @@
// don't like to use loads of #ifdefs, so duplicating GP2X code
// horribly instead
//#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
@ -16,6 +15,7 @@
#include <pspdisplay.h>
#include <pspgu.h>
#include <pspiofilemgr.h>
#include <psputils.h>
#include "psp.h"
#include "emu.h"
@ -39,11 +39,11 @@ static const char * const pspKeyNames[] = {
pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn
};
static unsigned char bg_buffer[480*272*2] __attribute__((aligned(16))); // TODO: move to vram?
static unsigned short bg_buffer[480*272] __attribute__((aligned(16)));
#define menu_screen psp_screen
static void menu_darken_bg(void *dst, const void *src, int pixels, int darker);
static void menu_prepare_bg(int use_game_bg);
static void menu_prepare_bg(int use_game_bg, int use_back_buff);
static unsigned int inp_prev = 0;
@ -495,24 +495,38 @@ static void state_check_slots(void)
}
}
static void *get_oldstate_for_preview(void)
{
unsigned char *ptr = malloc(sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram) + sizeof(Pico.video));
if (ptr == NULL) return NULL;
memcpy(ptr, Pico.vram, sizeof(Pico.vram));
memcpy(ptr + sizeof(Pico.vram), Pico.cram, sizeof(Pico.cram));
memcpy(ptr + sizeof(Pico.vram) + sizeof(Pico.cram), Pico.vsram, sizeof(Pico.vsram));
memcpy(ptr + sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram), &Pico.video, sizeof(Pico.video));
return ptr;
}
static void restore_oldstate(void *ptrx)
{
unsigned char *ptr = ptrx;
memcpy(Pico.vram, ptr, sizeof(Pico.vram));
memcpy(Pico.cram, ptr + sizeof(Pico.vram), sizeof(Pico.cram));
memcpy(Pico.vsram, ptr + sizeof(Pico.vram) + sizeof(Pico.cram), sizeof(Pico.vsram));
memcpy(&Pico.video,ptr + sizeof(Pico.vram) + sizeof(Pico.cram) + sizeof(Pico.vsram), sizeof(Pico.video));
free(ptrx);
}
static void draw_savestate_bg(int slot)
{
struct PicoVideo tmp_pv;
unsigned short tmp_cram[0x40];
unsigned short tmp_vsram[0x40];
void *tmp_vram, *file;
void *file, *oldstate;
char *fname;
fname = emu_GetSaveFName(1, 0, slot);
if (!fname) return;
tmp_vram = malloc(sizeof(Pico.vram));
if (tmp_vram == NULL) return;
memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));
memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));
memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));
memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));
oldstate = get_oldstate_for_preview();
if (oldstate == NULL) return;
if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {
file = gzopen(fname, "rb");
@ -538,13 +552,9 @@ static void draw_savestate_bg(int slot)
}
emu_forcedFrame();
menu_prepare_bg(1);
menu_prepare_bg(1, 1);
memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));
memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));
memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));
memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));
free(tmp_vram);
restore_oldstate(oldstate);
}
static void draw_savestate_menu(int menu_sel, int is_loading)
@ -595,7 +605,7 @@ static int savestate_menu_loop(int is_loading)
if(inp & BTN_X) { // save/load
if (menu_sel < 10) {
state_slot = menu_sel;
PicoStateProgressCB = emu_stateCb; /* also suitable for menu */
PicoStateProgressCB = emu_msg_cb; /* also suitable for menu */
if (emu_SaveLoadGame(is_loading, 0)) {
strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");
return 1;
@ -944,6 +954,150 @@ static void cd_menu_loop_options(void)
}
}
// --------- display options ----------
menu_entry opt3_entries[] =
{
{ NULL, MB_NONE, MA_OPT3_SCALE, NULL, 0, 0, 0, 1 },
{ NULL, MB_NONE, MA_OPT3_HSCALE32, NULL, 0, 0, 0, 1 },
{ NULL, MB_NONE, MA_OPT3_HSCALE40, NULL, 0, 0, 0, 1 },
{ NULL, MB_ONOFF, MA_OPT3_FILTERING, &currentConfig.scaling, 1, 0, 0, 1 },
{ "Set to unscaled centered", MB_NONE, MA_OPT3_PRES_NOSCALE, NULL, 0, 0, 0, 1 },
{ "Set to fullscreen", MB_NONE, MA_OPT3_PRES_FULLSCR, NULL, 0, 0, 0, 1 },
{ "done", MB_NONE, MA_OPT3_DONE, NULL, 0, 0, 0, 1 },
};
#define OPT3_ENTRY_COUNT (sizeof(opt3_entries) / sizeof(opt3_entries[0]))
static void menu_opt3_cust_draw(const menu_entry *entry, int x, int y, void *param)
{
switch (entry->id)
{
case MA_OPT3_SCALE:
text_out16(x, y, "Scale factor: %.2f", currentConfig.scale);
break;
case MA_OPT3_HSCALE32:
text_out16(x, y, "Hor. scale (for low res. games): %.2f", currentConfig.hscale32);
break;
case MA_OPT3_HSCALE40:
text_out16(x, y, "Hor. scale (for hi res. games): %.2f", currentConfig.hscale40);
break;
case MA_OPT3_FILTERING:
text_out16(x, y, "Bilinear filtering %s", currentConfig.scaling?"ON":"OFF");
break;
default: break;
}
}
static void menu_opt3_preview(int is_32col)
{
void *oldstate = NULL;
if (rom_data == NULL || ((Pico.video.reg[12]&1)^1) != is_32col)
{
extern char bgdatac32_start[], bgdatac40_start[];
extern int bgdatac32_size, bgdatac40_size;
void *bgdata = is_32col ? bgdatac32_start : bgdatac40_start;
unsigned long insize = is_32col ? bgdatac32_size : bgdatac40_size, outsize = 65856;
int ret;
lprintf("%p %p %i %i (n %p)\n", bgdatac32_start, bgdatac40_start, bgdatac32_size, bgdatac40_size, &engineState);
ret = uncompress((Bytef *)bg_buffer, &outsize, bgdata, insize);
if (ret == 0)
{
if (rom_data != NULL) oldstate = get_oldstate_for_preview();
memcpy(Pico.vram, bg_buffer, sizeof(Pico.vram));
memcpy(Pico.cram, (char *)bg_buffer + 0x10000, 0x40*2);
memcpy(Pico.vsram, (char *)bg_buffer + 0x10080, 0x40*2);
memcpy(&Pico.video,(char *)bg_buffer + 0x10100, 0x40);
}
else
lprintf("uncompress returned %i\n", ret);
}
memset32(psp_screen, 0, 512*272*2/4);
emu_forcedFrame();
menu_prepare_bg(1, 1);
if (oldstate) restore_oldstate(oldstate);
}
static void draw_dispmenu_options(int menu_sel)
{
int tl_x = 80+25, tl_y = 16+50;
menu_draw_begin();
menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);
me_draw(opt3_entries, OPT3_ENTRY_COUNT, tl_x, tl_y, menu_opt3_cust_draw, NULL);
menu_draw_end();
}
static void dispmenu_loop_options(void)
{
static int menu_sel = 0;
int menu_sel_max, is_32col = 0;
unsigned long inp = 0;
menu_id selected_id;
menu_sel_max = me_count_enabled(opt3_entries, OPT3_ENTRY_COUNT) - 1;
for(;;)
{
draw_dispmenu_options(menu_sel);
inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT|BTN_X|BTN_CIRCLE);
if (inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
if (inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
selected_id = me_index2id(opt3_entries, OPT3_ENTRY_COUNT, menu_sel);
if (selected_id == MA_OPT3_HSCALE40 && is_32col) { is_32col = 0; menu_opt3_preview(is_32col); }
if (selected_id == MA_OPT3_HSCALE32 && !is_32col) { is_32col = 1; menu_opt3_preview(is_32col); }
if (inp & (BTN_LEFT|BTN_RIGHT)) // multi choise
{
float *setting = NULL;
me_process(opt3_entries, OPT3_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0);
switch (selected_id) {
case MA_OPT3_SCALE: setting = &currentConfig.scale; break;
case MA_OPT3_HSCALE40: setting = &currentConfig.hscale40; is_32col = 0; break;
case MA_OPT3_HSCALE32: setting = &currentConfig.hscale32; is_32col = 1; break;
case MA_OPT3_FILTERING:menu_opt3_preview(is_32col); break;
default: break;
}
if (setting != NULL) {
while ((inp = psp_pad_read(0)) & (BTN_LEFT|BTN_RIGHT)) {
*setting += (inp & BTN_LEFT) ? -0.01 : 0.01;
menu_opt3_preview(is_32col);
draw_dispmenu_options(menu_sel); // will wait vsync
}
}
}
if (inp & BTN_X) { // toggleable options
me_process(opt3_entries, OPT3_ENTRY_COUNT, selected_id, 1);
switch (selected_id) {
case MA_OPT3_DONE:
return;
case MA_OPT3_PRES_NOSCALE:
currentConfig.scale = currentConfig.hscale40 = currentConfig.hscale32 = 1.0;
menu_opt3_preview(is_32col);
break;
case MA_OPT3_PRES_FULLSCR:
currentConfig.scale = 1.20;
currentConfig.hscale40 = 1.25;
currentConfig.hscale32 = 1.56;
menu_opt3_preview(is_32col);
break;
case MA_OPT3_FILTERING:
menu_opt3_preview(is_32col);
break;
default: break;
}
}
if (inp & BTN_CIRCLE) return;
}
}
// --------- advanced options ----------
@ -952,8 +1106,6 @@ menu_entry opt2_entries[] =
{ "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &currentConfig.PicoOpt,0x0004, 0, 0, 1 },
{ "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &currentConfig.PicoOpt,0x0001, 0, 0, 1 },
{ "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&currentConfig.PicoOpt,0x0002, 0, 0, 1 },
// { "Double buffering", MB_ONOFF, MA_OPT2_DBLBUFF, &currentConfig.EmuOpt, 0x8000, 0, 0, 1 },
// { "Wait for V-sync (slow)", MB_ONOFF, MA_OPT2_VSYNC, &currentConfig.EmuOpt, 0x2000, 0, 0, 1 },
{ "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, &currentConfig.EmuOpt, 0x0008, 0, 0, 1 },
{ "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, &currentConfig.EmuOpt, 0x0020, 0, 0, 1 },
{ "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1 },
@ -994,13 +1146,7 @@ static void amenu_loop_options(void)
if (inp & (BTN_LEFT|BTN_RIGHT)) { // multi choise
if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0) &&
selected_id == MA_OPT2_GAMMA) {
while ((inp = psp_pad_read(1)) & (BTN_LEFT|BTN_RIGHT)) {
currentConfig.gamma += (inp & BTN_LEFT) ? -1 : 1;
if (currentConfig.gamma < 1) currentConfig.gamma = 1;
if (currentConfig.gamma > 300) currentConfig.gamma = 300;
draw_amenu_options(menu_sel);
psp_msleep(18);
}
// TODO?
}
}
if (inp & BTN_X) { // toggleable options
@ -1032,8 +1178,9 @@ menu_entry opt_entries[] =
{ NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1 },
{ "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1 },
{ NULL, MB_NONE, MA_OPT_CPU_CLOCKS, NULL, 0, 0, 0, 1 },
{ "[Display options]", MB_NONE, MA_OPT_DISP_OPTS, NULL, 0, 0, 0, 1 },
{ "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1 },
{ "[advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1 },
{ "[Advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1 },
{ NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1 },
{ "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1 },
{ NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1 },
@ -1120,7 +1267,6 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
}
static void draw_menu_options(int menu_sel)
{
int tl_x = 80+25, tl_y = 16+24;
@ -1282,6 +1428,9 @@ static int menu_loop_options(void)
{
switch (selected_id)
{
case MA_OPT_DISP_OPTS:
dispmenu_loop_options();
break;
case MA_OPT_SCD_OPTS:
cd_menu_loop_options();
if (engineState == PGS_ReloadRom)
@ -1373,10 +1522,8 @@ static void draw_menu_root(int menu_sel)
me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);
// error
if (menuErrorMsg[0]) {
// memset((char *)menu_screen + 321*224*2, 0, 321*16*2);
text_out16(5, 258, menuErrorMsg);
}
if (menuErrorMsg[0])
text_out16(10, 252, menuErrorMsg);
menu_draw_end();
}
@ -1525,29 +1672,30 @@ static void menu_darken_bg(void *dst, const void *src, int pixels, int darker)
}
}
static void menu_prepare_bg(int use_game_bg)
static void menu_prepare_bg(int use_game_bg, int use_back_buff)
{
memset(bg_buffer, 0, sizeof(bg_buffer));
if (use_game_bg)
{
// darken the active framebuffer
/*
memset(bg_buffer, 0, 321*8*2);
menu_darken_bg(bg_buffer + 321*8*2, (char *)giz_screen + 321*8*2, 321*224, 1);
memset(bg_buffer + 321*232*2, 0, 321*8*2);
*/
unsigned short *dst = bg_buffer;
unsigned short *src = use_back_buff ? psp_screen : psp_video_get_active_fb();
int i;
for (i = 272; i > 0; i--, dst += 480, src += 512)
menu_darken_bg(dst, src, 480, 1);
//memset32((int *)(bg_buffer + 480*264), 0, 480*8*2/4);
}
else
{
// should really only happen once, on startup..
memset32((int *)(void *)bg_buffer, 0, sizeof(bg_buffer)/4);
readpng(bg_buffer, "skin/background.png", READPNG_BG);
}
sceKernelDcacheWritebackAll();
}
static void menu_gfx_prepare(void)
{
menu_prepare_bg(rom_data != NULL);
menu_prepare_bg(rom_data != NULL, 0);
menu_draw_begin();
menu_draw_end();

View file

@ -3,8 +3,6 @@
#ifndef PORT_CONFIG_H
#define PORT_CONFIG_H
#define CPU_CALL
// draw.c
#define USE_BGR555 1
#define OVERRIDE_HIGHCOL 1
@ -15,6 +13,8 @@
#define DRAW2_OVERRIDE_LINE_WIDTH 512
// pico.c
extern void blit1(void);
#define DRAW_FINISH_FUNC blit1
#define CAN_HANDLE_240_LINES 1
// logging emu events

View file

@ -64,34 +64,24 @@ void psp_init(void)
sceGuInit();
sceGuStart(GU_DIRECT, guCmdList);
sceGuDrawBuffer(GU_PSM_5650, VRAMOFFS_FB0, 512); // point to back fb?
sceGuDispBuffer(480, 272, VRAMOFFS_FB1, 512);
sceGuDrawBuffer(GU_PSM_5650, (void *)VRAMOFFS_FB0, 512);
sceGuDispBuffer(480, 272, (void *)VRAMOFFS_FB1, 512); // don't care
sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT);
sceGuDepthBuffer(VRAMOFFS_DEPTH, 512);
sceGuDepthBuffer((void *)VRAMOFFS_DEPTH, 512);
sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2));
sceGuViewport(2048, 2048, 480, 272);
sceGuDepthRange(0xc350, 0x2710);
sceGuScissor(0, 0, 480, 272);
sceGuEnable(GU_SCISSOR_TEST);
// sceGuAlphaFunc(GU_GREATER, 0, 0xff);
// sceGuEnable(GU_ALPHA_TEST);
// sceGuDepthFunc(GU_ALWAYS); // GU_GEQUAL);
// sceGuEnable(GU_DEPTH_TEST);
sceGuDepthMask(0xffff);
sceGuDisable(GU_DEPTH_TEST);
sceGuFrontFace(GU_CW);
// sceGuShadeModel(GU_SMOOTH);
// sceGuEnable(GU_CULL_FACE);
sceGuEnable(GU_TEXTURE_2D);
// sceGuEnable(GU_CLIP_PLANES);
sceGuTexMode(GU_PSM_5650, 0, 0, 0);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_NEAREST, GU_NEAREST);
// sceGuAmbientColor(0xffffffff);
// sceGuEnable(GU_BLEND);
// sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
sceGuAmbientColor(0xffffffff);
sceGuColor(0xffffffff);
sceGuFinish();
sceGuSync(0, 0);

View file

@ -9,19 +9,20 @@ void psp_msleep(int ms);
// 000000-044000 fb0
// 044000-088000 fb1
// 088000-0cc000 depth (?)
// 0cc000-0??000 stuff
// 0cc000-126000 emu draw buffers: 512*240 + 512*240*2
#define VRAMOFFS_FB0 ((void *) 0x00000000)
#define VRAMOFFS_FB1 ((void *) 0x00044000)
#define VRAMOFFS_DEPTH ((void *) 0x00088000)
#define VRAMOFFS_FB0 0x00000000
#define VRAMOFFS_FB1 0x00044000
#define VRAMOFFS_DEPTH 0x00088000
#define VRAMOFFS_STUFF 0x000cc000
#define VRAM_FB0 ((void *) 0x44000000)
#define VRAM_FB1 ((void *) 0x44044000)
#define VRAM_STUFF ((void *) 0x440cc000)
#define VRAM_FB0 ((void *) (0x44000000+VRAMOFFS_FB0))
#define VRAM_FB1 ((void *) (0x44000000+VRAMOFFS_FB1))
#define VRAM_STUFF ((void *) (0x44000000+VRAMOFFS_STUFF))
#define VRAM_CACHED_STUFF ((void *) 0x040cc000)
#define VRAM_CACHED_STUFF ((void *) (0x04000000+VRAMOFFS_STUFF))
#define GU_CMDLIST_SIZE (16*1024) // TODO: adjust
#define GU_CMDLIST_SIZE (16*1024)
extern unsigned int guCmdList[GU_CMDLIST_SIZE];
@ -48,5 +49,5 @@ int psp_set_cpu_clock(int clock);
#define BTN_SQUARE PSP_CTRL_SQUARE
#define BTN_SELECT PSP_CTRL_SELECT
#define BTN_START PSP_CTRL_START
#define BTN_NOTE PSP_CTRL_NOTE
#define BTN_NOTE PSP_CTRL_NOTE // doesn't seem to work?