From cdc6aac4c0398f628b9646db73decae399a6b948 Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 10 Jan 2021 12:09:18 +0100 Subject: [PATCH] partially revived platform support for PSP (unfinished) just to have a platform with an unusal screen resolution - suspend/resume handling probably non-working - no scaling settings - no image generation currently no intentions to finish this. --- Makefile | 27 + pico/32x/draw.c | 3 + pico/debug.c | 6 +- pico/draw.c | 6 +- pico/draw_arm.S | 2 +- pico/mode4.c | 5 +- platform/common/menu_pico.c | 22 +- platform/psp/emu.c | 874 +++++------------ platform/psp/emu.h | 4 +- platform/psp/in_psp.c | 214 +++++ platform/psp/in_psp.h | 4 + platform/psp/main.c | 3 +- platform/psp/menu.c | 1813 +---------------------------------- platform/psp/mp3.c | 13 +- platform/psp/plat.c | 314 ++++++ platform/psp/psp.c | 28 +- platform/psp/psp.h | 25 +- 17 files changed, 928 insertions(+), 2435 deletions(-) create mode 100644 platform/psp/in_psp.c create mode 100644 platform/psp/in_psp.h create mode 100644 platform/psp/plat.c diff --git a/Makefile b/Makefile index 673292b4..1cfd5ffa 100644 --- a/Makefile +++ b/Makefile @@ -34,10 +34,12 @@ gperf ?= 0 ifneq ("$(PLATFORM)", "libretro") CFLAGS += -Wall -g +ifneq ("$(PLATFORM)", "psp") ifneq ($(findstring gcc,$(shell $(CC) -v 2>&1)),) CFLAGS += -ffunction-sections -fdata-sections LDFLAGS += -Wl,--gc-sections endif +endif ifeq "$(DEBUG)" "0" CFLAGS += -O3 -DNDEBUG @@ -162,6 +164,20 @@ USE_FRONTEND = 1 PLATFORM_MP3 = 1 PLATFORM_ZLIB = 1 endif +ifeq "$(PLATFORM)" "psp" +CFLAGS += -DUSE_BGR565 -DDRAW2_OVERRIDE_LINE_WIDTH=512 -G8 # -DLPRINTF_STDIO -DFW15 +platform/common/main.o: CFLAGS += -Dmain=pico_main +OBJS += platform/psp/plat.o +OBJS += platform/psp/emu.o +OBJS += platform/psp/in_psp.o +OBJS += platform/psp/psp.o +#OBJS += platform/psp/menu.o +OBJS += platform/psp/asm_utils.o +OBJS += platform/psp/mp3.o +#OBJS += platform/psp/data/bg32.o +#OBJS += platform/psp/data/bg40.o +USE_FRONTEND = 1 +endif ifeq "$(PLATFORM)" "libretro" OBJS += platform/libretro/libretro.o ifeq "$(USE_LIBRETRO_VFS)" "1" @@ -207,6 +223,7 @@ endif endif # USE_FRONTEND +ifneq "$(PLATFORM)" "psp" OBJS += platform/common/mp3.o platform/common/mp3_sync.o ifeq "$(PLATFORM_MP3)" "1" OBJS += platform/common/mp3_helix.o @@ -215,6 +232,7 @@ OBJS += platform/common/mp3_libavcodec.o else OBJS += platform/common/mp3_minimp3.o endif +endif ifeq "$(PLATFORM_ZLIB)" "1" # zlib @@ -259,6 +277,15 @@ else $(LD) $(LINKOUT)$@ $^ $(LDFLAGS) $(LDLIBS) endif +ifeq "$(PLATFORM)" "psp" +PSPSDK = /home/.build/opt/pspdev/psp/sdk +PSP_EBOOT_TITLE = PicoDrive +LIBS += -lpng -lm -lz -lpspgu -lpsppower -lpspaudio -lpsprtc -lpspaudiocodec +EXTRA_TARGETS = EBOOT.PBP +include /home/.build/opt/pspdev/psp/sdk/lib/build.mak +# TODO image generation +endif + pprof: platform/linux/pprof.c $(CC) $(CFLAGS) -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@ $(LDFLAGS) $(LDLIBS) diff --git a/pico/32x/draw.c b/pico/32x/draw.c index 6954eca9..3ca858d6 100644 --- a/pico/32x/draw.c +++ b/pico/32x/draw.c @@ -12,6 +12,9 @@ #if defined(USE_BGR555) #define PXCONV(t) (t) #define PXPRIO 0x8000 // prio in MSB +#elif defined(USE_BGR565) +#define PXCONV(t) (((t)&m1) | (((t)&(m2|m3)) << 1)) +#define PXPRIO 0x0020 // prio in LS green bit #else // RGB565 #define PXCONV(t) ((((t)&m1) << 11) | (((t)&m2) << 1) | (((t)&m3) >> 10)) #define PXPRIO 0x0020 // prio in LS green bit diff --git a/pico/debug.c b/pico/debug.c index e4b5232e..51cc903f 100644 --- a/pico/debug.c +++ b/pico/debug.c @@ -148,7 +148,11 @@ char *PDebugSpriteList(void) } #define GREEN1 0x0700 -#ifdef USE_BGR555 +#if defined(USE_BGR555) + #define YELLOW1 0x039c + #define BLUE1 0x7800 + #define RED1 0x001e +#elif defined(USE_BGR565) #define YELLOW1 0x071c #define BLUE1 0xf000 #define RED1 0x001e diff --git a/pico/draw.c b/pico/draw.c index 8aa39dea..3f397963 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -69,6 +69,10 @@ u32 VdpSATCache[128]; // VDP sprite cache (1st 32 sprite attr bits) #define PXCONV(t) ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<2) | ((t & 0x0e000e00)<<3) #define PXMASKL 0x04210421 // 0x0c630c63, LSB for all colours #define PXMASKH 0x39ce39ce // 0x3def3def, all but MSB for all colours +#elif defined(USE_BGR565) +#define PXCONV(t) ((t & 0x000e000e)<< 1) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)<<4) +#define PXMASKL 0x08610861 // 0x18e318e3 +#define PXMASKH 0x738e738e // 0x7bef7bef #else // RGB565 #define PXCONV(t) ((t & 0x000e000e)<<12) | ((t & 0x00e000e0)<<3) | ((t & 0x0e000e00)>>7) #define PXMASKL 0x08610861 // 0x18e318e3 @@ -2004,7 +2008,7 @@ void PicoDrawSetOutFormat(pdso_t which, int use_32x_line_mode) void PicoDrawSetOutBufMD(void *dest, int increment) { - if (FinalizeLine == FinalizeLine8bit && increment == 328) { + if (FinalizeLine == FinalizeLine8bit && increment >= 328) { // kludge for no-copy mode PicoDrawSetInternalBuf(dest, increment); } diff --git a/pico/draw_arm.S b/pico/draw_arm.S index 8b717a50..e05c2fd4 100644 --- a/pico/draw_arm.S +++ b/pico/draw_arm.S @@ -8,7 +8,7 @@ * * this is highly specialized, be careful if changing related C code! * - * NB only does RGB565 output, BGR555 isn't supported + * NB only does RGB565 output, BGR isn't supported */ #include "pico_int_offs.h" diff --git a/pico/mode4.c b/pico/mode4.c index f8ce6467..9e853d47 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -337,9 +337,12 @@ void PicoDoHighPal555M4(void) /* cram is always stored as shorts, even though real hardware probably uses bytes */ for (i = 0x20/2; i > 0; i--, spal++, dpal++) { t = *spal; -#ifdef USE_BGR555 +#if defined(USE_BGR555) t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<6) | ((t & 0x00300030)<<9); t |= (t >> 2) | ((t >> 4) & 0x04210421); +#elif defined(USE_BGR565) + t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)<<10); + t |= (t >> 2) | ((t >> 4) & 0x08610861); #else t = ((t & 0x00030003)<<14) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)>>1); t |= (t >> 2) | ((t >> 4) & 0x08610861); diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 46519540..fe9f032d 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -23,6 +23,17 @@ #define MENU_X2 0 #endif +#if defined USE_BGR555 +#define COL_ROM 0x5eff +#define COL_OTH 0x5ff5 +#elif defined USE_BGR565 +#define COL_ROM 0xfdf7 +#define COL_OTH 0xaff5 +#else +#define COL_ROM 0xbdff +#define COL_OTH 0xaff5 +#endif + // FIXME #define REVISION "0" @@ -49,9 +60,9 @@ static unsigned short fname2color(const char *fname) } for (i = 0; rom_exts[i] != NULL; i++) - if (strcasecmp(ext, rom_exts[i]) == 0) return 0xbdff; // FIXME: mk defines + if (strcasecmp(ext, rom_exts[i]) == 0) return COL_ROM; for (i = 0; i < array_size(other_exts); i++) - if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5; + if (strcasecmp(ext, other_exts[i]) == 0) return COL_OTH; return 0xffff; } @@ -62,6 +73,8 @@ static const char *men_dummy[] = { NULL }; /* platform specific options and handlers */ #if defined(__GP2X__) #include +#elif defined(__PSP__) +#include #elif defined(PANDORA) #include #else @@ -72,8 +85,9 @@ static const char *men_dummy[] = { NULL }; static void make_bg(int no_scale) { unsigned short *src = (void *)g_menubg_src_ptr; - int w = g_screen_width, h = g_screen_height; - int pp = g_screen_ppitch; + int w = g_menubg_src_w ? g_menubg_src_w : g_screen_width; + int h = g_menubg_src_h ? g_menubg_src_h : g_screen_height; + int pp = g_menubg_src_pp ? g_menubg_src_pp : g_screen_ppitch; short *dst; int x, y; diff --git a/platform/psp/emu.c b/platform/psp/emu.c index 93e55c95..1b4a90ee 100644 --- a/platform/psp/emu.c +++ b/platform/psp/emu.c @@ -17,40 +17,104 @@ #include #include "psp.h" -#include "menu.h" #include "emu.h" #include "mp3.h" +#include "in_psp.h" #include "asm_utils.h" #include "../common/emu.h" -#include "../common/config.h" +#include "../common/input_pico.h" +#include "platform/libpicofe/input.h" +#include "platform/libpicofe/menu.h" + #include +#include +#include #include #define OSD_FPS_X 432 -// additional pspaudio imports, credits to crazyc -int sceAudio_38553111(unsigned short samples, unsigned short freq, char unknown); // play with conversion? -int sceAudio_5C37C0AE(void); // end play? -int sceAudio_E0727056(int volume, void *buffer); // blocking output -int sceAudioOutput2GetRestSample(); - - -//unsigned char *Draw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword.. int engineStateSuspend; #define PICO_PEN_ADJUST_X 4 #define PICO_PEN_ADJUST_Y 2 -static int pico_pen_x = 320/2, pico_pen_y = 240/2; -static void sound_init(void); -static void sound_deinit(void); -static void blit2(const char *fps, const char *notice, int lagging_behind); -static void clearArea(int full); +struct Vertex +{ + short u,v; + short x,y,z; +}; + +static struct Vertex __attribute__((aligned(4))) g_vertices[2]; +static unsigned short __attribute__((aligned(16))) localPal[0x100]; +static int need_pal_upload = 0; +static int fbimg_offs = 0; +static int h32_mode = 0; + +static const struct in_default_bind in_psp_defbinds[] = +{ + { PSP_CTRL_UP, IN_BINDTYPE_PLAYER12, GBTN_UP }, + { PSP_CTRL_DOWN, IN_BINDTYPE_PLAYER12, GBTN_DOWN }, + { PSP_CTRL_LEFT, IN_BINDTYPE_PLAYER12, GBTN_LEFT }, + { PSP_CTRL_RIGHT, IN_BINDTYPE_PLAYER12, GBTN_RIGHT }, + { PSP_CTRL_SQUARE, IN_BINDTYPE_PLAYER12, GBTN_A }, + { PSP_CTRL_CROSS, IN_BINDTYPE_PLAYER12, GBTN_B }, + { PSP_CTRL_CIRCLE, IN_BINDTYPE_PLAYER12, GBTN_C }, + { PSP_CTRL_START, IN_BINDTYPE_PLAYER12, GBTN_START }, + { PSP_CTRL_TRIANGLE, IN_BINDTYPE_EMU, PEVB_SWITCH_RND }, + { PSP_CTRL_LTRIGGER, IN_BINDTYPE_EMU, PEVB_STATE_SAVE }, + { PSP_CTRL_RTRIGGER, IN_BINDTYPE_EMU, PEVB_STATE_LOAD }, + { PSP_CTRL_SELECT, IN_BINDTYPE_EMU, PEVB_MENU }, + { 0, 0, 0 } +}; + -int plat_get_root_dir(char *dst, int len) +const char *renderer_names[] = { "16bit accurate", " 8bit accurate", " 8bit fast", NULL }; +const char *renderer_names32x[] = { "accurate", "faster", "fastest", NULL }; +enum renderer_types { RT_16BIT, RT_8BIT_ACC, RT_8BIT_FAST, RT_COUNT }; + +#define is_16bit_mode() \ + (get_renderer() == RT_16BIT || (PicoIn.AHW & PAHW_32X)) + +static int get_renderer(void) { - if (len > 0) *dst = 0; - return 0; + if (PicoIn.AHW & PAHW_32X) + return currentConfig.renderer32x; + else + return currentConfig.renderer; +} + +static void change_renderer(int diff) +{ + int *r; + if (PicoIn.AHW & PAHW_32X) + r = ¤tConfig.renderer32x; + else + r = ¤tConfig.renderer; + *r += diff; + + if (*r >= RT_COUNT) + *r = 0; + else if (*r < 0) + *r = RT_COUNT - 1; +} + +static void apply_renderer(void) +{ + PicoIn.opt &= ~POPT_ALT_RENDERER; + PicoIn.opt |= POPT_DIS_32C_BORDER; + + switch (currentConfig.renderer) { + case RT_16BIT: + PicoDrawSetOutFormat(PDF_RGB555, 0); + break; + case RT_8BIT_ACC: + PicoDrawSetOutFormat(PDF_8BIT, 0); + break; + case RT_8BIT_FAST: + PicoIn.opt |= POPT_ALT_RENDERER; + PicoDrawSetOutFormat(PDF_NONE, 0); + break; + } } static void osd_text(int x, const char *text, int is_active, int clear_all) @@ -58,80 +122,18 @@ static void osd_text(int x, const char *text, int is_active, int clear_all) unsigned short *screen = is_active ? psp_video_get_active_fb() : psp_screen; int len = clear_all ? (480 / 2) : (strlen(text) * 8 / 2); int *p, h; - void *tmp; + void *tmp = g_screen_ptr; for (h = 0; h < 8; h++) { p = (int *) (screen+x+512*(264+h)); p = (int *) ((int)p & ~3); // align memset32_uncached(p, 0, len); } - if (is_active) { tmp = psp_screen; psp_screen = screen; } // nasty pointer tricks + g_screen_ptr = screen; // nasty pointer tricks emu_text_out16(x, 264, text); - if (is_active) psp_screen = tmp; -} - -void emu_msg_cb(const char *msg) -{ - osd_text(4, msg, 1, 1); - noticeMsgTime = sceKernelGetSystemTimeLow() - 2000000; - - /* assumption: emu_msg_cb gets called only when something slow is about to happen */ - reset_timing = 1; -} - -/* FIXME: move to plat */ -void emu_Init(void) -{ - sound_init(); -} - -void emu_Deinit(void) -{ - sound_deinit(); -} - -void pemu_prep_defconfig(void) -{ - defaultConfig.s_PsndRate = 22050; - defaultConfig.s_PicoCDBuffers = 64; - defaultConfig.CPUclock = 333; - defaultConfig.KeyBinds[ 4] = 1<<0; // SACB RLDU - defaultConfig.KeyBinds[ 6] = 1<<1; - defaultConfig.KeyBinds[ 7] = 1<<2; - defaultConfig.KeyBinds[ 5] = 1<<3; - defaultConfig.KeyBinds[14] = 1<<4; - defaultConfig.KeyBinds[13] = 1<<5; - defaultConfig.KeyBinds[15] = 1<<6; - defaultConfig.KeyBinds[ 3] = 1<<7; - defaultConfig.KeyBinds[12] = 1<<26; // switch rnd - defaultConfig.KeyBinds[ 8] = 1<<27; // save state - defaultConfig.KeyBinds[ 9] = 1<<28; // load state - defaultConfig.KeyBinds[28] = 1<<0; // num "buttons" - defaultConfig.KeyBinds[30] = 1<<1; - defaultConfig.KeyBinds[31] = 1<<2; - defaultConfig.KeyBinds[29] = 1<<3; - defaultConfig.scaling = 1; // bilinear filtering for psp - defaultConfig.scale = 1.20; // fullscreen - defaultConfig.hscale40 = 1.25; - defaultConfig.hscale32 = 1.56; + g_screen_ptr = tmp; } -extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count); -extern void amips_clut_6bit(unsigned short *dst, unsigned char *src, unsigned short *pal, int count); - -static void (*amips_clut_f)(unsigned short *dst, unsigned char *src, unsigned short *pal, int count) = NULL; - -struct Vertex -{ - short u,v; - 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, border_hack = 0; @@ -139,7 +141,7 @@ static void set_scaling_params(void) g_vertices[0].z = g_vertices[1].z = 0; fbimg_height = (int)(240.0 * currentConfig.scale + 0.5); - if (Pico.video.reg[12] & 1) { + if (!h32_mode) { fbimg_width = (int)(320.0 * currentConfig.scale * currentConfig.hscale40 + 0.5); src_width = 320; } else { @@ -183,6 +185,11 @@ static void set_scaling_params(void) g_vertices[1].u--; g_vertices[1].x--; } + if (!is_16bit_mode()) { + // 8-bit modes have an 8 px overlap area on the left + g_vertices[0].u += 8; + g_vertices[1].u += 8; + } fbimg_offs = (fbimg_yoffs*512 + fbimg_xoffs) * 2; // dst is always 16bit /* @@ -193,109 +200,55 @@ static void set_scaling_params(void) */ } -static void do_pal_update(int allow_sh, int allow_as) +static void do_pal_update(void) { 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 ((currentConfig.EmuOpt&0x80) || (PicoOpt&0x10)) { - do_pal_convert(localPal, Pico.cram, currentConfig.gamma, currentConfig.gamma2); + if (PicoIn.opt & POPT_ALT_RENDERER) { + do_pal_convert(localPal, PicoMem.cram, currentConfig.gamma, currentConfig.gamma2); Pico.m.dirtyPal = 0; } - else if (Pico.est.rendstatus&0x20) + else if (Pico.est.rendstatus & PDRAW_SONIC_MODE) { switch (Pico.est.SonicPalCount) { - case 3: do_pal_convert(localPal+0xc0, Pico.est.SonicPal+0xc0, currentConfig.gamma, currentConfig.gamma2); - case 2: do_pal_convert(localPal+0x80, Pico.est.SonicPal+0x80, currentConfig.gamma, currentConfig.gamma2); - case 1: do_pal_convert(localPal+0x40, Pico.est.SonicPal+0x40, currentConfig.gamma, currentConfig.gamma2); + case 3: do_pal_convert(localPal+0xc0/2, Pico.est.SonicPal+0xc0, currentConfig.gamma, currentConfig.gamma2); + case 2: do_pal_convert(localPal+0x80/2, Pico.est.SonicPal+0x80, currentConfig.gamma, currentConfig.gamma2); + case 1: do_pal_convert(localPal+0x40/2, Pico.est.SonicPal+0x40, currentConfig.gamma, currentConfig.gamma2); default:do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2); } } - else if (allow_sh && (Pico.video.reg[0xC]&8)) // shadow/hilight? + else if (Pico.video.reg[0xC]&8) // shadow/hilight? { do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2); // shadowed pixels - for (i = 0x3f/2; i >= 0; i--) - dpal[0x20|i] = dpal[0x60|i] = (dpal[i]>>1)&0x7bcf7bcf; + for (i = 0; i < 0x40 / 2; i++) { + dpal[0xc0/2 + i] = dpal[i]; + dpal[0x80/2 + i] = (dpal[i] >> 1) & 0x738e738e; + } // hilighted pixels - for (i = 0x3f; i >= 0; i--) { - int t=localPal[i]&0xf79e;t+=0x4208; - if (t&0x20) t|=0x1e; - if (t&0x800) t|=0x780; - if (t&0x10000) t|=0xf000; - t&=0xf79e; - localPal[0x80|i]=(unsigned short)t; + for (i = 0; i < 0x40 / 2; i++) { + u32 t = ((dpal[i] >> 1) & 0x738e738e) + 0x738e738e; + t |= (t >> 4) & 0x08610861; + dpal[0x40/2 + i] = t; } - localPal[0xe0] = 0; - localPal[0xf0] = 0x001f; } - else if (allow_as && (Pico.est.rendstatus & PDRAW_SPR_LO_ON_HI)) + else { do_pal_convert(localPal, Pico.est.SonicPal, currentConfig.gamma, currentConfig.gamma2); memcpy((int *)dpal+0x40/2, (void *)localPal, 0x40*2); memcpy((int *)dpal+0x80/2, (void *)localPal, 0x80*2); } + localPal[0xe0] = 0; + localPal[0xf0] = 0x001f; if (Pico.m.dirtyPal == 2) 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_f(dst, src, localPal, line_len); -} - -static void EmuScanPrepare(void) -{ - Pico.est.HighCol = (unsigned char *)VRAM_CACHED_STUFF + 8; - if (!(Pico.video.reg[1]&8)) Pico.est.HighCol += 8*512; - - if (dynamic_palette > 0) - dynamic_palette--; - - if (Pico.m.dirtyPal) - do_pal_update(1, 1); - if (!(Pico.video.reg[0xC] & 8)) - amips_clut_f = amips_clut_6bit; - else amips_clut_f = amips_clut; -} - -static int EmuScanSlowBegin(unsigned int num) -{ - if (!dynamic_palette) - Pico.est.HighCol = (unsigned char *)VRAM_CACHED_STUFF + num * 512 + 8; - - return 0; -} - -static int EmuScanSlowEnd(unsigned int num) -{ - if (Pico.m.dirtyPal) { - if (!dynamic_palette) { - do_slowmode_lines(num); - dynamic_palette = 3; // last for 2 more frames - } - do_pal_update(1, 1); - } - - 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_f(dst, Pico.est.HighCol + 8, localPal, line_len); - } - - return 0; -} - static void blitscreen_clut(void) { int offs = fbimg_offs; @@ -304,34 +257,17 @@ static void blitscreen_clut(void) sceGuSync(0,0); // sync with prev sceGuStart(GU_DIRECT, guCmdList); sceGuDrawBuffer(GU_PSM_5650, (void *)offs, 512); // point to back buffer + sceGuTexMode(is_16bit_mode() ? GU_PSM_5650:GU_PSM_T8,0,0,0); + sceGuTexImage(0,512,512,512,g_screen_ptr); - if (dynamic_palette) - { - if (!blit_16bit_mode) { // the current mode is not 16bit - 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 ((PicoIn.opt&0x10) && Pico.m.dirtyPal) - do_pal_update(0, 0); + if (Pico.m.dirtyPal) + do_pal_update(); - sceKernelDcacheWritebackAll(); + sceKernelDcacheWritebackAll(); - if (need_pal_upload) { - need_pal_upload = 0; - sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256) - } + if (need_pal_upload) { + need_pal_upload = 0; + sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256) } #if 1 @@ -376,10 +312,10 @@ static void cd_leds(void) static void draw_pico_ptr(void) { - unsigned char *p = (unsigned char *)VRAM_STUFF + 16; + unsigned char *p = (unsigned char *)VRAM_CACHED_STUFF + 8; // only if pen enabled and for 8bit mode - if (pico_inp_mode == 0 || blit_16bit_mode) return; + if (pico_inp_mode == 0 || is_16bit_mode()) return; p += 512 * (pico_pen_y + PICO_PEN_ADJUST_Y); p += pico_pen_x + PICO_PEN_ADJUST_X; @@ -389,76 +325,17 @@ static void draw_pico_ptr(void) } -#if 0 -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_uncached(p, 0, len); - } - emu_text_out16(2, 256, text); -} -#endif - -/* called after rendering is done, but frame emulation is not finished */ -void blit1(void) -{ - if (PicoIn.opt&0x10) - { - int i; - unsigned char *pd; - // clear top and bottom trash - for (pd = Pico.est.Draw2FB+8, i = 8; i > 0; i--, pd += 512) - memset32((int *)pd, 0xe0e0e0e0, 320/4); - for (pd = Pico.est.Draw2FB+512*232+8, i = 8; i > 0; i--, pd += 512) - memset32((int *)pd, 0xe0e0e0e0, 320/4); - } - - if (PicoIn.AHW & PAHW_PICO) - draw_pico_ptr(); - - blitscreen_clut(); -} - - -static void blit2(const char *fps, const char *notice, int lagging_behind) -{ - int vsync = 0, emu_opt = currentConfig.EmuOpt; - - if (notice || (emu_opt & 2)) { - if (notice) osd_text(4, notice, 0, 0); - if (emu_opt & 2) osd_text(OSD_FPS_X, fps, 0, 0); - } - - //dbg_text(); - - if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD)) - cd_leds(); - - if (currentConfig.EmuOpt & 0x2000) { // want vsync - if (!(currentConfig.EmuOpt & 0x10000) || !lagging_behind) vsync = 1; - } - - psp_video_flip(vsync); -} - // clears whole screen or just the notice area (in all buffers) static void clearArea(int full) { + void *fb = psp_video_get_active_fb(); + if (full) { memset32_uncached(psp_screen, 0, 512*272*2/4); - psp_video_flip(0); - memset32_uncached(psp_screen, 0, 512*272*2/4); + memset32_uncached(fb, 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_uncached((int *)((char *)psp_screen + 512*264*2), 0, 512*8*2/4); memset32_uncached((int *)((char *)fb + 512*264*2), 0, 512*8*2/4); } @@ -471,7 +348,6 @@ static void vidResetMode(void) sceGuStart(GU_DIRECT, guCmdList); sceGuClutMode(GU_PSM_5650,0,0xff,0); - sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB); if (currentConfig.scaling) sceGuTexFilter(GU_LINEAR, GU_LINEAR); @@ -479,28 +355,13 @@ static void vidResetMode(void) sceGuTexScale(1.0f,1.0f); sceGuTexOffset(0.0f,0.0f); - sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 16); - - // slow rend. - PicoDrawSetOutFormat(PDF_NONE, 0); - PicoDrawSetCallbacks(EmuScanSlowBegin, EmuScanSlowEnd); - - localPal[0xe0] = 0; - localPal[0xf0] = 0x001f; Pico.m.dirtyPal = 1; - blit_16bit_mode = dynamic_palette = 0; sceGuFinish(); set_scaling_params(); sceGuSync(0,0); } -void plat_debug_cat(char *str) -{ - strcat(str, blit_16bit_mode ? "soft clut\n" : "hard clut\n"); -} - - /* sound stuff */ #define SOUND_BLOCK_SIZE_NTSC (1470*2) // 1024 // 1152 #define SOUND_BLOCK_SIZE_PAL (1764*2) @@ -533,7 +394,7 @@ static int sound_thread(SceSize args, void *argp) // lprintf("sthr: got data: %i\n", samples_made - samples_done); - ret = sceAudio_E0727056(PSP_AUDIO_VOLUME_MAX, snd_playptr); + ret = sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, snd_playptr); samples_done += samples_block; snd_playptr += samples_block; @@ -541,7 +402,7 @@ static int sound_thread(SceSize args, void *argp) snd_playptr = sndBuffer; // 1.5 kernel returns 0, newer ones return # of samples queued if (ret < 0) - lprintf("sthr: sceAudio_E0727056: %08x; pos %i/%i\n", ret, samples_done, samples_made); + lprintf("sthr: sceAudioSRCOutputBlocking: %08x; pos %i/%i\n", ret, samples_done, samples_made); // shouln't happen, but just in case if (samples_made - samples_done >= samples_block*3) { @@ -581,10 +442,20 @@ static void sound_init(void) void pemu_sound_start(void) { static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0; + static int mp3_init_done; int ret, stereo; samples_made = samples_done = 0; + if (PicoIn.AHW & PAHW_MCD) { + // mp3... + if (!mp3_init_done) { + ret = mp3_init(); + mp3_init_done = 1; + if (ret) emu_status_msg("mp3 init failed (%i)", ret); + } + } + if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) { PsndRerate(Pico.m.frame_count ? 1 : 0); } @@ -598,10 +469,10 @@ void pemu_sound_start(void) PicoIn.sndRate, Pico.snd.len, stereo, Pico.m.pal, samples_block); // while (sceAudioOutput2GetRestSample() > 0) psp_msleep(100); - // sceAudio_5C37C0AE(); - ret = sceAudio_38553111(samples_block/2, PicoIn.sndRate, 2); // seems to not need that stupid 64byte alignment + // sceAudioSRCChRelease(); + ret = sceAudioSRCChReserve(samples_block/2, PicoIn.sndRate, 2); // seems to not need that stupid 64byte alignment if (ret < 0) { - lprintf("sceAudio_38553111() failed: %i\n", ret); + lprintf("sceAudioSRCChReserve() failed: %i\n", ret); emu_status_msg("sound init failed (%i), snd disabled", ret); currentConfig.EmuOpt &= ~EOPT_EN_SOUND; } else { @@ -621,8 +492,8 @@ void pemu_sound_stop(void) int i; if (samples_done == 0) { - // if no data is written between sceAudio_38553111 and sceAudio_5C37C0AE calls, - // we get a deadlock on next sceAudio_38553111 call + // if no data is written between sceAudioSRCChReserve and sceAudioSRCChRelease calls, + // we get a deadlock on next sceAudioSRCChReserve call // so this is yet another workaround: memset32((int *)(void *)sndBuffer, 0, samples_block*4/4); samples_made = samples_block * 3; @@ -632,7 +503,7 @@ void pemu_sound_stop(void) samples_made = samples_done = 0; for (i = 0; sceAudioOutput2GetRestSample() > 0 && i < 16; i++) psp_msleep(100); - sceAudio_5C37C0AE(); + sceAudioSRCChRelease(); } /* wait until we can write more sound */ @@ -676,387 +547,164 @@ static void writeSound(int len) } -static void SkipFrame(void) +/* set default configuration values */ +void pemu_prep_defconfig(void) { - PicoIn.skipFrame=1; - PicoFrame(); - PicoIn.skipFrame=0; + defaultConfig.s_PsndRate = 22050; + defaultConfig.s_PicoCDBuffers = 64; + defaultConfig.CPUclock = 333; + defaultConfig.scaling = 1; // bilinear filtering for psp + defaultConfig.scale = 1.20; // fullscreen + defaultConfig.hscale40 = 1.25; + defaultConfig.hscale32 = 1.56; } -void pemu_forced_frame(int no_scale, int do_emu) +/* check configuration for inconsistencies */ +void pemu_validate_config(void) { - int po_old = PicoIn.opt; - int eo_old = currentConfig.EmuOpt; + if (currentConfig.CPUclock < 33 || currentConfig.CPUclock > 333) + currentConfig.CPUclock = 333; +} - PicoIn.opt &= ~POPT_ALT_RENDERER; - PicoIn.opt |= POPT_ACC_SPRITES; - if (!no_scale && defaultConfig.scaling) - PicoIn.opt |= POPT_EN_SOFTSCALE; - currentConfig.EmuOpt |= 0x80; +/* finalize rendering a frame */ +void pemu_finalize_frame(const char *fps, const char *notice) +{ + int emu_opt = currentConfig.EmuOpt; - vidResetMode(); - memset32(VRAM_CACHED_STUFF, 0xe0e0e0e0, 512*8/4); // borders - memset32((int *)VRAM_CACHED_STUFF + 512*232/4, 0xe0e0e0e0, 512*8/4); - memset32_uncached((int *)psp_screen + 512*264*2/4, 0, 512*8*2/4); - - PicoDrawSetOutFormat(PDF_NONE, 0); - PicoDrawSetCallbacks(EmuScanSlowBegin, EmuScanSlowEnd); - EmuScanPrepare(); - PicoFrameDrawOnly(); - blit1(); - sceGuSync(0,0); + if (PicoIn.AHW & PAHW_PICO) + draw_pico_ptr(); + + blitscreen_clut(); - PicoIn.opt = po_old; - currentConfig.EmuOpt = eo_old; + // XXX move this to flip to give texture renderer more time? + if (notice) osd_text(4, notice, 0, 0); + if (emu_opt & 2) osd_text(OSD_FPS_X, fps, 0, 0); + + if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD)) + cd_leds(); } +/* FIXME: move plat_* to plat? */ -static void RunEventsPico(unsigned int events, unsigned int keys) +void plat_debug_cat(char *str) { - emu_RunEventsPico(events); - - if (pico_inp_mode != 0) - { - PicoIn.pad[0] &= ~0x0f; // release UDLR - if (keys & PBTN_UP) { pico_pen_y--; if (pico_pen_y < 8) pico_pen_y = 8; } - if (keys & PBTN_DOWN) { pico_pen_y++; if (pico_pen_y > 224-PICO_PEN_ADJUST_Y) pico_pen_y = 224-PICO_PEN_ADJUST_Y; } - if (keys & PBTN_LEFT) { pico_pen_x--; if (pico_pen_x < 0) pico_pen_x = 0; } - if (keys & PBTN_RIGHT) { - int lim = (Pico.video.reg[12]&1) ? 319 : 255; - pico_pen_x++; - if (pico_pen_x > lim-PICO_PEN_ADJUST_X) - pico_pen_x = lim-PICO_PEN_ADJUST_X; - } - PicoPicohw.pen_pos[0] = pico_pen_x; - if (!(Pico.video.reg[12]&1)) PicoPicohw.pen_pos[0] += pico_pen_x/4; - PicoPicohw.pen_pos[0] += 0x3c; - PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y); - } } -static void RunEvents(unsigned int which) +/* platform dependend emulator initialization */ +void plat_init(void) { - if (which & 0x1800) // save or load (but not both) - { - int do_it = 1; - - if ( emu_check_save_file(state_slot) && - (( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load - (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) // save - { - int keys; - sceGuSync(0,0); - blit2("", (which & 0x1000) ? "LOAD STATE? (X=yes, O=no)" : "OVERWRITE SAVE? (X=yes, O=no)", 0); - while( !((keys = psp_pad_read(1)) & (PBTN_X|PBTN_CIRCLE)) ) - psp_msleep(50); - if (keys & PBTN_CIRCLE) do_it = 0; - while( ((keys = psp_pad_read(1)) & (PBTN_X|PBTN_CIRCLE)) ) // wait for release - psp_msleep(50); - clearArea(0); - } - - if (do_it) - { - osd_text(4, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME", 1, 0); - PicoStateProgressCB = emu_msg_cb; - emu_save_load_game((which & 0x1000) >> 12, 0); - PicoStateProgressCB = NULL; - psp_msleep(0); - } - - reset_timing = 1; - } - if (which & 0x0400) // switch renderer - { - if (PicoIn.opt&0x10) { PicoIn.opt&=~0x10; currentConfig.EmuOpt |= 0x80; } - else { PicoIn.opt|= 0x10; currentConfig.EmuOpt &= ~0x80; } - - vidResetMode(); + flip_after_sync = 1; + in_psp_init(in_psp_defbinds); + in_probe(); + sound_init(); +} - if (PicoIn.opt & POPT_ALT_RENDERER) - emu_status_msg("fast renderer"); - else if (currentConfig.EmuOpt&0x80) - emu_status_msg("accurate renderer"); - } - if (which & 0x0300) - { - if(which&0x0200) { - state_slot -= 1; - if(state_slot < 0) state_slot = 9; - } else { - state_slot += 1; - if(state_slot > 9) state_slot = 0; - } - emu_status_msg("SAVE SLOT %i [%s]", state_slot, - emu_check_save_file(state_slot) ? "USED" : "FREE"); - } +/* platform dependend emulator deinitialization */ +void plat_finish(void) +{ + sound_deinit(); } -static void updateKeys(void) +/* display emulator status messages before holding emulation */ +void plat_status_msg_busy_first(const char *msg) { - unsigned int keys, allActions[2] = { 0, 0 }, events; - static unsigned int prevEvents = 0; - int i; + plat_status_msg_busy_next(msg); +} - /* FIXME: port to input fw, merge with emu.c:emu_update_input() */ - keys = psp_pad_read(0); - if (keys & PSP_CTRL_HOME) - sceDisplayWaitVblankStart(); +void plat_status_msg_busy_next(const char *msg) +{ + plat_status_msg_clear(); + pemu_finalize_frame("", msg); + plat_video_flip(); + emu_status_msg(""); + reset_timing = 1; +} - if (keys & PBTN_SELECT) - engineState = PGS_Menu; +/* clear status message area */ +void plat_status_msg_clear(void) +{ + clearArea(0); +} - keys &= CONFIGURABLE_KEYS; +/* change the audio volume setting */ +void plat_update_volume(int has_changed, int is_up) +{ +} - PicoIn.pad[0] = allActions[0] & 0xfff; - PicoIn.pad[1] = allActions[1] & 0xfff; +/* prepare for MD screen mode change */ +void emu_video_mode_change(int start_line, int line_count, int is_32cols) +{ + h32_mode = is_32cols; + vidResetMode(); + if (h32_mode) // clear borders from h40 remnants + clearArea(1); +} - if (allActions[0] & 0x7000) emu_DoTurbo(&PicoIn.pad[0], allActions[0]); - if (allActions[1] & 0x7000) emu_DoTurbo(&PicoIn.pad[1], allActions[1]); +/* render one frame in RGB */ +void pemu_forced_frame(int no_scale, int do_emu) +{ + PicoIn.opt &= ~POPT_DIS_32C_BORDER; + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + Pico.m.dirtyPal = 1; - events = (allActions[0] | allActions[1]) >> 16; + if (!no_scale) + no_scale = currentConfig.scaling == EOPT_SCALE_NONE; + emu_cmn_forced_frame(no_scale, do_emu); +} - if ((events ^ prevEvents) & 0x40) { - emu_set_fastforward(events & 0x40); - reset_timing = 1; - } +/* change the platform output rendering */ +void plat_video_toggle_renderer(int change, int is_menu_call) +{ + change_renderer(change); - events &= ~prevEvents; + if (is_menu_call) + return; - if (PicoIn.AHW == PAHW_PICO) - RunEventsPico(events, keys); - if (events) RunEvents(events); - if (movie_data) emu_updateMovie(); + apply_renderer(); + vidResetMode(); + rendstatus_old = -1; - prevEvents = (allActions[0] | allActions[1]) >> 16; + if (PicoIn.AHW & PAHW_32X) + emu_status_msg(renderer_names32x[get_renderer()]); + else + emu_status_msg(renderer_names[get_renderer()]); } - -static void simpleWait(unsigned int until) +/* set the buffer for emulator output rendering */ +void plat_video_set_buffer(void *buf) { - unsigned int tval; - int diff; - - tval = sceKernelGetSystemTimeLow(); - diff = (int)until - (int)tval; - if (diff >= 512 && diff < 100*1024) - sceKernelDelayThread(diff); + if (currentConfig.renderer == RT_16BIT || (PicoIn.AHW & PAHW_32X)) + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch * 2); + else + PicoDrawSetOutBuf(g_screen_ptr, g_screen_ppitch); } -void pemu_loop(void) +/* prepare for emulator output rendering */ +void plat_video_loop_prepare(void) { - static int mp3_init_done = 0; - char fpsbuff[24]; // fps count c string - unsigned int tval, tval_thissec = 0; // timing - int target_fps, target_frametime, lim_time, tval_diff, i, oldmodes = 0; - int pframes_done, pframes_shown; // "period" frames, used for sync - int frames_done, frames_shown, tval_fpsc = 0; // actual frames - char *notice = NULL; - - lprintf("entered emu_Loop()\n"); - - fpsbuff[0] = 0; - - if (currentConfig.CPUclock != psp_get_cpu_clock()) { - lprintf("setting cpu clock to %iMHz... ", currentConfig.CPUclock); - i = psp_set_cpu_clock(currentConfig.CPUclock); - lprintf(i ? "failed\n" : "done\n"); - currentConfig.CPUclock = psp_get_cpu_clock(); - } - - // make sure we are in correct mode + apply_renderer(); vidResetMode(); clearArea(1); - Pico.m.dirtyPal = 1; - oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc; - - // pal/ntsc might have changed, reset related stuff - target_fps = Pico.m.pal ? 50 : 60; - target_frametime = Pico.m.pal ? (1000000<<8)/50 : (1000000<<8)/60+1; - reset_timing = 1; - - if (PicoIn.AHW & PAHW_MCD) { - // prepare CD buffer - PicoCDBufferInit(); - // mp3... - if (!mp3_init_done) { - i = mp3_init(); - mp3_init_done = 1; - if (i) { engineState = PGS_Menu; return; } - } - } - - // prepare sound stuff - PicoIn.sndOut = NULL; - if (currentConfig.EmuOpt & EOPT_EN_SOUND) - { - pemu_sound_start(); - } - - sceDisplayWaitVblankStart(); - pframes_shown = pframes_done = - frames_shown = frames_done = 0; - - tval_fpsc = sceKernelGetSystemTimeLow(); - - // loop? - while (engineState == PGS_Running) - { - int modes; - - tval = sceKernelGetSystemTimeLow(); - if (reset_timing || tval < tval_fpsc) { - //stdbg("timing reset"); - reset_timing = 0; - tval_thissec = tval; - pframes_shown = pframes_done = 0; - } - - // show notice message? - if (noticeMsgTime) { - static int noticeMsgSum; - if (tval - noticeMsgTime > 2000000) { // > 2.0 sec - noticeMsgTime = 0; - clearArea(0); - notice = 0; - } else { - int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2]; - if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; } - notice = noticeMsg; - } - } - - // check for mode changes - modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8); - if (modes != oldmodes) { - oldmodes = modes; - clearArea(1); - set_scaling_params(); - } - - // second passed? - if (tval - tval_fpsc >= 1000000) - { - if (currentConfig.EmuOpt & 2) - sprintf(fpsbuff, "%02i/%02i ", frames_shown, frames_done); - frames_done = frames_shown = 0; - tval_fpsc += 1000000; - } - - if (tval - tval_thissec >= 1000000) - { - // missing 1 frame? - if (currentConfig.Frameskip < 0 && pframes_done < target_fps) { - SkipFrame(); pframes_done++; frames_done++; - } - - tval_thissec += 1000000; - - if (currentConfig.Frameskip < 0) { - pframes_done -= target_fps; if (pframes_done < 0) pframes_done = 0; - pframes_shown -= target_fps; if (pframes_shown < 0) pframes_shown = 0; - if (pframes_shown > pframes_done) pframes_shown = pframes_done; - } else { - pframes_done = pframes_shown = 0; - } - } -#ifdef PFRAMES - sprintf(fpsbuff, "%i", Pico.m.frame_count); -#endif - - lim_time = (pframes_done+1) * target_frametime; - if (currentConfig.Frameskip >= 0) // frameskip enabled - { - for (i = 0; i < currentConfig.Frameskip; i++) { - updateKeys(); - SkipFrame(); pframes_done++; frames_done++; - if (!(currentConfig.EmuOpt&0x40000)) { // do framelimitting if needed - int tval_diff; - tval = sceKernelGetSystemTimeLow(); - tval_diff = (int)(tval - tval_thissec) << 8; - if (tval_diff < lim_time) // we are too fast - simpleWait(tval + ((lim_time - tval_diff)>>8)); - } - lim_time += target_frametime; - } - } - else // auto frameskip - { - int tval_diff; - tval = sceKernelGetSystemTimeLow(); - tval_diff = (int)(tval - tval_thissec) << 8; - if (tval_diff > lim_time && (pframes_done/16 < pframes_shown)) - { - // no time left for this frame - skip - if (tval_diff - lim_time >= (300000<<8)) { - reset_timing = 1; - continue; - } - updateKeys(); - SkipFrame(); pframes_done++; frames_done++; - continue; - } - } - - updateKeys(); - - if (!(PicoIn.opt&0x10)) - EmuScanPrepare(); - - PicoFrame(); - - sceGuSync(0,0); - - // check time - tval = sceKernelGetSystemTimeLow(); - tval_diff = (int)(tval - tval_thissec) << 8; - - blit2(fpsbuff, notice, tval_diff > lim_time); - - if (currentConfig.Frameskip < 0 && tval_diff - lim_time >= (300000<<8)) { // slowdown detection - reset_timing = 1; - } - else if (!(currentConfig.EmuOpt&0x40000) || currentConfig.Frameskip < 0) - { - // sleep if we are still too fast - if (tval_diff < lim_time) - { - // we are too fast - simpleWait(tval + ((lim_time - tval_diff) >> 8)); - } - } - - pframes_done++; pframes_shown++; - frames_done++; frames_shown++; - } - - - emu_set_fastforward(0); - - if (PicoIn.AHW & PAHW_MCD) PicoCDBufferFree(); - - if (PicoIn.sndOut != NULL) { - pemu_sound_stop(); - PicoIn.sndOut = NULL; - } +} - // save SRAM - if ((currentConfig.EmuOpt & 1) && SRam.changed) { - emu_msg_cb("Writing SRAM/BRAM.."); - emu_save_load_game(0, 1); - SRam.changed = 0; - } +/* prepare for entering the emulator loop */ +void pemu_loop_prep(void) +{ +} - // clear fps counters and stuff - memset32_uncached((int *)psp_video_get_active_fb() + 512*264*2/4, 0, 512*8*2/4); +/* terminate the emulator loop */ +void pemu_loop_end(void) +{ + pemu_sound_stop(); } -void emu_HandleResume(void) +// TODO +void emu_handle_resume(void) { if (!(PicoIn.AHW & PAHW_MCD)) return; // reopen first CD track - if (Pico_mcd->TOC.Tracks[0].F != NULL) + if (cdd.toc.tracks[0].fd != NULL) { char *fname = rom_fname_reload; int len = strlen(rom_fname_reload); @@ -1070,16 +718,18 @@ void emu_HandleResume(void) } lprintf("emu_HandleResume: reopen %s\n", fname); - pm_close(Pico_mcd->TOC.Tracks[0].F); - Pico_mcd->TOC.Tracks[0].F = pm_open(fname); - lprintf("reopen %s\n", Pico_mcd->TOC.Tracks[0].F != NULL ? "ok" : "failed"); + pm_close(cdd.toc.tracks[0].fd); + cdd.toc.tracks[0].fd = pm_open(fname); + lprintf("reopen %s\n", cdd.toc.tracks[0].fd != NULL ? "ok" : "failed"); if (cue_data != NULL) cue_destroy(cue_data); } mp3_reopen_file(); - if (!(Pico_mcd->s68k_regs[0x36] & 1) && (Pico_mcd->scd.Status_CDC & 1)) - cdda_start_play(); +#if 0 // TODO + if (!(Pico_mcd->s68k_regs[0x36] & 1)/* && (Pico_mcd->scd.Status_CDC & 1)*/) + cdd_change_track(cdd.index, cdd.lba); +#endif } diff --git a/platform/psp/emu.h b/platform/psp/emu.h index 4ef53834..e9202745 100644 --- a/platform/psp/emu.h +++ b/platform/psp/emu.h @@ -1,9 +1,7 @@ extern int engineStateSuspend; -void emu_HandleResume(void); - -void emu_msg_cb(const char *msg); +void emu_handle_resume(void); // actually comes from Pico/Misc_amips.s void memset32_uncached(int *dest, int c, int count); diff --git a/platform/psp/in_psp.c b/platform/psp/in_psp.c new file mode 100644 index 00000000..4f9e2f48 --- /dev/null +++ b/platform/psp/in_psp.c @@ -0,0 +1,214 @@ +/* + * (C) Gražvydas "notaz" Ignotas, 2006-2012 + * (C) kub 2020 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * - MAME license. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../libpicofe/input.h" +#include "psp.h" +#include "in_psp.h" + +#define IN_PSP_PREFIX "psp:" +#define IN_PSP_NBUTTONS 32 + +/* note: in_psp handles combos (if 2 btns have the same bind, + * both must be pressed for action to happen) */ +static int in_psp_combo_keys = 0; +static int in_psp_combo_acts = 0; + + +static const char *in_psp_keys[IN_PSP_NBUTTONS] = { + [0 ... IN_PSP_NBUTTONS-1] = NULL, +}; + + +/* credits to https://graphics.stanford.edu/~seander/bithacks.html */ +static int lg2(unsigned v) +{ + int r, s; + + r = (v > 0xFFFF) << 4; v >>= r; + s = (v > 0xFF ) << 3; v >>= s; r |= s; + s = (v > 0xF ) << 2; v >>= s; r |= s; + s = (v > 0x3 ) << 1; v >>= s; r |= s; + r |= (v >> 1); + return r; +} + +static int in_psp_get_bits(void) +{ + return psp_pad_read(0); +} + +static void in_psp_probe(const in_drv_t *drv) +{ + in_register(IN_PSP_PREFIX "PSP pad", -1, NULL, + IN_PSP_NBUTTONS, in_psp_keys, 1); +} + +static void in_psp_free(void *drv_data) +{ +} + +static const char * const * +in_psp_get_key_names(const in_drv_t *drv, int *count) +{ + *count = IN_PSP_NBUTTONS; + return in_psp_keys; +} + +/* ORs result with pressed buttons */ +static int in_psp_update(void *drv_data, const int *binds, int *result) +{ + int type_start = 0; + int i, t, keys; + + keys = in_psp_get_bits(); + + if (keys & in_psp_combo_keys) { + result[IN_BINDTYPE_EMU] = in_combos_do(keys, binds, IN_PSP_NBUTTONS, + in_psp_combo_keys, in_psp_combo_acts); + type_start = IN_BINDTYPE_PLAYER12; + } + + for (i = 0; keys; i++, keys >>= 1) { + if (!(keys & 1)) + continue; + + for (t = type_start; t < IN_BINDTYPE_COUNT; t++) + result[t] |= binds[IN_BIND_OFFS(i, t)]; + } + + return 0; +} + +int in_psp_update_keycode(void *data, int *is_down) +{ + static int old_val = 0; + int val, diff, i; + + val = in_psp_get_bits(); + diff = val ^ old_val; + if (diff == 0) + return -1; + + /* take one bit only */ + for (i = 0; i < sizeof(diff)*8; i++) + if (diff & (1< kc */ + keycode = -keycode; + for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) + if (key_pbtn_map[i].pbtn == keycode) + return lg2(key_pbtn_map[i].key); + } + else + { + for (i = 0; i < KEY_PBTN_MAP_SIZE; i++) + if (key_pbtn_map[i].key == 1< -#include -#include -#include -#include // PATH_MAX +static const char *men_scaler[] = { "unscaled", "4:3", "fullscreen", NULL }; +#if 0 +static const char h_cscaler40[] = "Configures the custom scaler for wide resolution"; +static const char h_cscaler32[] = "Configures the custom scaler for narrow resolution"; -#include -#include -#include -#include - -#include "psp.h" -#include "emu.h" -#include "menu.h" -#include "mp3.h" -#include "../common/menu.h" -#include "../common/emu.h" -#include "../common/readpng.h" -#include "../common/input.h" -#include "../common/version.h" - -#include -#include -#include - - -#define pspKeyUnkn "???" -const char * const keyNames[] = { - "SELECT", pspKeyUnkn, pspKeyUnkn, "START", "UP", "RIGHT", "DOWN", "LEFT", - "L", "R", pspKeyUnkn, pspKeyUnkn, "TRIANGLE", "CIRCLE", "X", "SQUARE", - "HOME", "HOLD", "WLAN_UP", "REMOTE", "VOLUP", "VOLDOWN", "SCREEN", "NOTE", - pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, pspKeyUnkn, "NUB UP", "NUB RIGHT", "NUB DOWN", "NUB LEFT" // fake -}; - -static unsigned short bg_buffer[480*272] __attribute__((aligned(16))); -#define menu_screen psp_screen - -void menu_darken_bg(void *dst, const void *src, int pixels, int darker); -static void menu_prepare_bg(int use_game_bg, int use_fg); - - -void menu_draw_begin(void) -{ - // short *src = (short *)bg_buffer, *dst = (short *)menu_screen; - // int i; - - // for (i = 272; i >= 0; i--, dst += 512, src += 480) - // memcpy((int *)dst, (int *)src, 480*2); - - sceGuSync(0,0); // sync with prev - sceGuStart(GU_DIRECT, guCmdList); - sceGuCopyImage(GU_PSM_5650, 0, 0, 480, 272, 480, bg_buffer, 0, 0, 512, menu_screen); - sceGuFinish(); - sceGuSync(0,0); -} - - -void menu_draw_end(void) -{ - psp_video_flip(1); -} - - -// --------- loading ROM screen ---------- - -static int lcdr_line = 0; - -static void load_progress_cb(int percent) -{ - int ln, len = percent * 480 / 100; - unsigned short *dst; - - //sceDisplayWaitVblankStart(); - - dst = (unsigned short *)menu_screen + 512*10*lcdr_line; - - if (len > 480) len = 480; - for (ln = 8; ln > 0; ln--, dst += 512) - memset(dst, 0xff, len*2); -} - -static void cdload_progress_cb(int percent) -{ - int ln, len = percent * 480 / 100; - unsigned short *dst; - - if (lcdr_line <= 2) { - lcdr_line++; - smalltext_out16(1, lcdr_line++ * 10, "Processing CD image / MP3s", 0xffff); - smalltext_out16_lim(1, lcdr_line++ * 10, romFileName, 0xffff, 80); - } - - dst = (unsigned short *)menu_screen + 512*10*lcdr_line; - - if (len > 480) len = 480; - for (ln = 8; ln > 0; ln--, dst += 512) - memset(dst, 0xff, len*2); -} - -void menu_romload_prepare(const char *rom_name) -{ - const char *p = rom_name + strlen(rom_name); - while (p > rom_name && *p != '/') p--; - - psp_video_switch_to_single(); - if (rom_loaded) menu_draw_begin(); - else memset32_uncached(psp_screen, 0, 512*272*2/4); - - smalltext_out16(1, 1, "Loading", 0xffff); - smalltext_out16_lim(1, 10, p, 0xffff, 80); - PicoCartLoadProgressCB = load_progress_cb; - PicoCDLoadProgressCB = cdload_progress_cb; - lcdr_line = 2; -} - -void menu_romload_end(void) -{ - PicoCartLoadProgressCB = PicoCDLoadProgressCB = NULL; - smalltext_out16(1, ++lcdr_line*10, "Starting emulation...", 0xffff); -} - -// -------------- ROM selector -------------- - -struct my_dirent -{ - unsigned int d_type; - char d_name[255]; -}; - -// bbbb bggg gggr rrrr -static unsigned short file2color(const char *fname) -{ - const char *ext = fname + strlen(fname) - 3; - static const char *rom_exts[] = { "zip", "bin", "smd", "gen", "iso", "cso", "cue" }; - static const char *other_exts[] = { "gmv", "pat" }; - int i; - - if (ext < fname) ext = fname; - for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++) - if (strcasecmp(ext, rom_exts[i]) == 0) return 0xfdf7; - for (i = 0; i < sizeof(other_exts)/sizeof(other_exts[0]); i++) - if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5; - return 0xffff; -} - -static void draw_dirlist(char *curdir, struct my_dirent **namelist, int n, int sel) -{ - int start, i, pos; - - start = 13 - sel; - n--; // exclude current dir (".") - - menu_draw_begin(); - - if (!rom_loaded) { -// menu_darken_bg(menu_screen, menu_screen, 321*240, 0); - } - - menu_darken_bg((char *)menu_screen + 512*129*2, (char *)menu_screen + 512*129*2, 512*10, 0); - - if (start - 2 >= 0) - smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2); - for (i = 0; i < n; i++) { - pos = start + i; - if (pos < 0) continue; - if (pos > 26) break; - if (namelist[i+1]->d_type & FIO_S_IFDIR) { - smalltext_out16_lim(14, pos*10, "/", 0xd7ff, 1); - smalltext_out16_lim(14+6, pos*10, namelist[i+1]->d_name, 0xd7ff, 80-3); - } else { - unsigned short color = file2color(namelist[i+1]->d_name); - smalltext_out16_lim(14, pos*10, namelist[i+1]->d_name, color, 80-2); - } - } - text_out16(5, 130, ">"); - menu_draw_end(); -} - -static int scandir_cmp(const void *p1, const void *p2) +static int menu_loop_cscaler(int id, int keys) { - struct my_dirent **d1 = (struct my_dirent **)p1, **d2 = (struct my_dirent **)p2; - if ((*d1)->d_type & (*d2)->d_type & FIO_S_IFDIR) - return strcasecmp((*d1)->d_name, (*d2)->d_name); - if ((*d1)->d_type & FIO_S_IFDIR) return -1; // put before - if ((*d2)->d_type & FIO_S_IFDIR) return 1; - return strcasecmp((*d1)->d_name, (*d2)->d_name); -} - -static char *filter_exts[] = { - ".mp3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html", - ".jpg", ".pbp" -}; - -static int scandir_filter(const struct my_dirent *ent) -{ - const char *p; - int i; - - if (ent == NULL || ent->d_name == NULL) return 0; - if (strlen(ent->d_name) < 5) return 1; - - p = ent->d_name + strlen(ent->d_name) - 4; - - for (i = 0; i < sizeof(filter_exts)/sizeof(filter_exts[0]); i++) - { - if (strcasecmp(p, filter_exts[i]) == 0) return 0; - } - - return 1; -} - -static int my_scandir(const char *dir, struct my_dirent ***namelist_out, - int(*filter)(const struct my_dirent *), - int(*compar)(const void *, const void *)) -{ - int ret = -1, dir_uid = -1, name_alloc = 4, name_count = 0; - struct my_dirent **namelist = NULL, *ent; - SceIoDirent sce_ent; - - namelist = malloc(sizeof(*namelist) * name_alloc); - if (namelist == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } - - // try to read first.. - dir_uid = sceIoDopen(dir); - if (dir_uid >= 0) - { - /* it is very important to clear SceIoDirent to be passed to sceIoDread(), */ - /* or else it may crash, probably misinterpreting something in it. */ - memset(&sce_ent, 0, sizeof(sce_ent)); - ret = sceIoDread(dir_uid, &sce_ent); - if (ret < 0) - { - lprintf("sceIoDread(\"%s\") failed with %i\n", dir, ret); - goto fail; - } - } - else - lprintf("sceIoDopen(\"%s\") failed with %i\n", dir, dir_uid); - - while (ret > 0) - { - ent = malloc(sizeof(*ent)); - if (ent == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } - ent->d_type = sce_ent.d_stat.st_mode; - strncpy(ent->d_name, sce_ent.d_name, sizeof(ent->d_name)); - ent->d_name[sizeof(ent->d_name)-1] = 0; - if (filter == NULL || filter(ent)) - namelist[name_count++] = ent; - else free(ent); - - if (name_count >= name_alloc) - { - void *tmp; - name_alloc *= 2; - tmp = realloc(namelist, sizeof(*namelist) * name_alloc); - if (tmp == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } - namelist = tmp; - } - - memset(&sce_ent, 0, sizeof(sce_ent)); - ret = sceIoDread(dir_uid, &sce_ent); - } - - // sort - if (compar != NULL && name_count > 3) qsort(&namelist[2], name_count - 2, sizeof(namelist[0]), compar); - - // all done. - ret = name_count; - *namelist_out = namelist; - goto end; - -fail: - if (namelist != NULL) - { - while (name_count--) - free(namelist[name_count]); - free(namelist); - } -end: - if (dir_uid >= 0) sceIoDclose(dir_uid); - return ret; -} + unsigned int inp; + currentConfig.scaling = SCALE_CUSTOM; -static SceIoStat cpstat; - -static char *romsel_loop(char *curr_path) -{ - struct my_dirent **namelist; - int n, iret, sel = 0; - unsigned long inp = 0; - char *ret = NULL, *fname = NULL; - - // is this a dir or a full path? - memset(&cpstat, 0, sizeof(cpstat)); - iret = sceIoGetstat(curr_path, &cpstat); - if (iret >= 0 && (cpstat.st_mode & FIO_S_IFDIR)); // dir - else if (iret >= 0 && (cpstat.st_mode & FIO_S_IFREG)) { // file - char *p; - for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--); - if (p > curr_path) { - *p = 0; - fname = p+1; - } - else strcpy(curr_path, "ms0:/"); - } - else strcpy(curr_path, "ms0:/"); // something else - - n = my_scandir(curr_path, &namelist, scandir_filter, scandir_cmp); - if (n < 0) { - // try root.. - n = my_scandir("ms0:/", &namelist, scandir_filter, scandir_cmp); - if (n < 0) { - // oops, we failed - lprintf("scandir failed, dir: "); lprintf(curr_path); lprintf("\n"); - return NULL; - } - } - - // try to find sel - if (fname != NULL) { - int i; - for (i = 1; i < n; i++) { - if (strcmp(namelist[i]->d_name, fname) == 0) { - sel = i - 1; - break; - } - } - } + pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch); + pnd_restore_layer_data(); for (;;) { - draw_dirlist(curr_path, namelist, n, sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R|PBTN_X|PBTN_CIRCLE, 0); - if(inp & PBTN_UP ) { sel--; if (sel < 0) sel = n-2; } - if(inp & PBTN_DOWN) { sel++; if (sel > n-2) sel = 0; } - if(inp & PBTN_LEFT) { sel-=10; if (sel < 0) sel = 0; } - if(inp & PBTN_L) { sel-=24; if (sel < 0) sel = 0; } - if(inp & PBTN_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; } - if(inp & PBTN_R) { sel+=24; if (sel > n-2) sel = n-2; } - if(inp & PBTN_CIRCLE) // enter dir/select - { - if (namelist[sel+1]->d_type & FIO_S_IFDIR) - { - int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2; - char *p, *newdir = malloc(newlen); - if (strcmp(namelist[sel+1]->d_name, "..") == 0) { - char *start = curr_path; - p = start + strlen(start) - 1; - while (*p == '/' && p > start) p--; - while (*p != '/' && *p != ':' && p > start) p--; - if (p <= start || *p == ':') strcpy(newdir, "ms0:/"); - else { strncpy(newdir, start, p-start); newdir[p-start] = 0; } - } else { - strcpy(newdir, curr_path); - p = newdir + strlen(newdir) - 1; - while (*p == '/' && p >= newdir) *p-- = 0; - strcat(newdir, "/"); - strcat(newdir, namelist[sel+1]->d_name); - } - ret = romsel_loop(newdir); - free(newdir); - break; - } - else if (namelist[sel+1]->d_type & FIO_S_IFREG) - { - strcpy(romFileName, curr_path); - strcat(romFileName, "/"); - strcat(romFileName, namelist[sel+1]->d_name); - ret = romFileName; - break; - } - } - if(inp & PBTN_X) break; // cancel - } - - if (n > 0) { - while(n--) free(namelist[n]); - free(namelist); - } - - return ret; -} - -// ------------ patch/gg menu ------------ - -static void draw_patchlist(int sel) -{ - int start, i, pos, active; - - start = 13 - sel; - - menu_draw_begin(); - - for (i = 0; i < PicoPatchCount; i++) { - pos = start + i; - if (pos < 0) continue; - if (pos > 26) break; - active = PicoPatches[i].active; - smalltext_out16_lim(14, pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3); - smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6); - } - pos = start + i; - if (pos < 27) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4); - - text_out16(5, 130, ">"); - menu_draw_end(); -} - - -static void patches_menu_loop(void) -{ - int menu_sel = 0; - unsigned long inp = 0; + menu_draw_begin(0, 1); + menuscreen_memset_lines(g_menuscreen_ptr, 0, g_menuscreen_h); + text_out16(2, 480 - 18, "%dx%d | d-pad to resize, R+d-pad to move", g_layer_cw, g_layer_ch); + menu_draw_end(); - for(;;) - { - draw_patchlist(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R|PBTN_X|PBTN_CIRCLE, 0); - if(inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; } - if(inp & PBTN_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; } - if(inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; } - if(inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; } - if(inp & PBTN_CIRCLE) { // action - if (menu_sel < PicoPatchCount) - PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active; - else return; - } - if(inp & PBTN_X) return; - } - -} - -// ------------ savestate loader ------------ - -static int state_slot_flags = 0; - -static void state_check_slots(void) -{ - int slot; - - state_slot_flags = 0; - - for (slot = 0; slot < 10; slot++) - { - if (emu_checkSaveFile(slot)) - { - state_slot_flags |= 1 << slot; - } - } -} - -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) -{ - void *file, *oldstate; - char *fname; - - fname = emu_GetSaveFName(1, 0, slot); - if (!fname) return; - - oldstate = get_oldstate_for_preview(); - if (oldstate == NULL) return; - - if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) { - file = gzopen(fname, "rb"); - emu_setSaveStateCbs(1); - } else { - file = fopen(fname, "rb"); - emu_setSaveStateCbs(0); - } - - if (file) { - if (PicoIn.AHW & PAHW_MCD) { - PicoCdLoadStateGfx(file); - } else { - areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file - areaRead(Pico.vram, 1, sizeof(Pico.vram), file); - areaSeek(file, 0x2000, SEEK_CUR); - areaRead(Pico.cram, 1, sizeof(Pico.cram), file); - areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file); - areaSeek(file, 0x221a0, SEEK_SET); - areaRead(&Pico.video, 1, sizeof(Pico.video), file); - } - areaClose(file); - } - - emu_forcedFrame(0); - menu_prepare_bg(1, 0); - - restore_oldstate(oldstate); -} - -static void draw_savestate_menu(int menu_sel, int is_loading) -{ - int tl_x = 80+25, tl_y = 16+60, y, i; - - if (state_slot_flags & (1 << menu_sel)) - draw_savestate_bg(menu_sel); - menu_draw_begin(); - - text_out16(tl_x, 16+30, is_loading ? "Load state" : "Save state"); - - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108); - - /* draw all 10 slots */ - y = tl_y; - for (i = 0; i < 10; i++, y+=10) - { - text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free"); - } - text_out16(tl_x, y, "back"); - - menu_draw_end(); -} - -static int savestate_menu_loop(int is_loading) -{ - static int menu_sel = 10; - int menu_sel_max = 10; - unsigned long inp = 0; - - state_check_slots(); - - for(;;) - { - draw_savestate_menu(menu_sel, is_loading); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_X|PBTN_CIRCLE, 0); - if(inp & PBTN_UP ) { - do { - menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; - } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading); - } - if(inp & PBTN_DOWN) { - do { - menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; - } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading); - } - if(inp & PBTN_CIRCLE) { // save/load - if (menu_sel < 10) { - state_slot = menu_sel; - PicoStateProgressCB = emu_msg_cb; /* also suitable for menu */ - if (emu_SaveLoadGame(is_loading, 0)) { - strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed"); - return 1; - } - return 0; - } else return 1; - } - if(inp & PBTN_X) return 1; - } -} - -// -------------- key config -------------- - -static char *action_binds(int player_idx, int action_mask) -{ - static char strkeys[32*5]; - int i; - - strkeys[0] = 0; - for (i = 0; i < 32; i++) // i is key index - { - if (currentConfig.KeyBinds[i] & action_mask) - { - if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue; - if (strkeys[0]) { - strcat(strkeys, i >= 28 ? ", " : " + "); // nub "buttons" don't create combos - strcat(strkeys, keyNames[i]); - break; - } - else strcpy(strkeys, keyNames[i]); + inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT + |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40); + if (inp & PBTN_UP) g_layer_cy--; + if (inp & PBTN_DOWN) g_layer_cy++; + if (inp & PBTN_LEFT) g_layer_cx--; + if (inp & PBTN_RIGHT) g_layer_cx++; + if (!(inp & PBTN_R)) { + if (inp & PBTN_UP) g_layer_ch += 2; + if (inp & PBTN_DOWN) g_layer_ch -= 2; + if (inp & PBTN_LEFT) g_layer_cw += 2; + if (inp & PBTN_RIGHT) g_layer_cw -= 2; } - } - - return strkeys; -} - -static void unbind_action(int action) -{ - int i; - - for (i = 0; i < 32; i++) - currentConfig.KeyBinds[i] &= ~action; -} - -static int count_bound_keys(int action, int pl_idx) -{ - int i, keys = 0; - - for (i = 0; i < 32; i++) - { - if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue; - if (currentConfig.KeyBinds[i] & action) keys++; - } - - return keys; -} - -static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel) -{ - int x, y, tl_y = 16+20, i; - - menu_draw_begin(); - if (player_idx >= 0) { - text_out16(80+80, 16, "Player %i controls", player_idx + 1); - x = 80+80; - } else { - text_out16(80+80, 16, "Emulator controls"); - x = 80+40; - } - - menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130); - - y = tl_y; - for (i = 0; i < opt_cnt; i++, y+=10) - text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask)); - - text_out16(x, y, "Done"); - - if (sel < opt_cnt) { - text_out16(80+30, 220, "Press a button to bind/unbind"); - text_out16(80+30, 230, "Use SELECT to clear"); - text_out16(80+30, 240, "To bind UP/DOWN, hold SELECT"); - text_out16(80+30, 250, "Select \"Done\" to exit"); - } else { - text_out16(80+30, 230, "Use Options -> Save cfg"); - text_out16(80+30, 240, "to save controls"); - text_out16(80+30, 250, "Press X or O to exit"); - } - menu_draw_end(); -} - -static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx) -{ - int sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i; - unsigned long inp = 0; - - for (;;) - { - draw_key_config(opts, opt_cnt, player_idx, sel); - inp = in_menu_wait(CONFIGURABLE_KEYS|PBTN_SELECT, 1); - if (!(inp & PBTN_SELECT)) { - prev_select = 0; - if(inp & PBTN_UP ) { sel--; if (sel < 0) sel = menu_sel_max; continue; } - if(inp & PBTN_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; } - } - if (sel >= opt_cnt) { - if (inp & (PBTN_X|PBTN_CIRCLE)) break; - else continue; - } - // if we are here, we want to bind/unbind something - if ((inp & PBTN_SELECT) && !prev_select) - unbind_action(opts[sel].mask); - prev_select = inp & PBTN_SELECT; - inp &= CONFIGURABLE_KEYS; - inp &= ~PBTN_SELECT; - for (i = 0; i < 32; i++) - if (inp & (1 << i)) { - if (count_bound_keys(opts[sel].mask, player_idx) >= 2) - currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only - else currentConfig.KeyBinds[i] ^= opts[sel].mask; - if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) { - currentConfig.KeyBinds[i] &= ~(3 << 16); - currentConfig.KeyBinds[i] |= player_idx << 16; - } - } - } -} - -menu_entry ctrlopt_entries[] = -{ - { "Player 1", MB_NONE, MA_CTRL_PLAYER1, NULL, 0, 0, 0, 1, 0 }, - { "Player 2", MB_NONE, MA_CTRL_PLAYER2, NULL, 0, 0, 0, 1, 0 }, - { "Emulator controls", MB_NONE, MA_CTRL_EMU, NULL, 0, 0, 0, 1, 0 }, - { "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoIn.opt, 0x020, 0, 0, 1, 1 }, - { "Turbo rate", MB_RANGE, MA_CTRL_TURBO_RATE, ¤tConfig.turbo_rate, 0, 1, 30, 1, 1 }, - { "Done", MB_NONE, MA_CTRL_DONE, NULL, 0, 0, 0, 1, 0 }, -}; - -#define CTRLOPT_ENTRY_COUNT (sizeof(ctrlopt_entries) / sizeof(ctrlopt_entries[0])) -const int ctrlopt_entry_count = CTRLOPT_ENTRY_COUNT; - -static void draw_kc_sel(int menu_sel) -{ - int tl_x = 80+25+40, tl_y = 16+60, y; - - y = tl_y; - menu_draw_begin(); - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138); - - me_draw(ctrlopt_entries, ctrlopt_entry_count, tl_x, tl_y, NULL, NULL); - - menu_draw_end(); -} - - -// player2_flag, ?, ?, ?, ?, ?, ?, menu -// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE", -// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE" -me_bind_action emuctrl_actions[] = -{ - { "Load State ", 1<<28 }, - { "Save State ", 1<<27 }, - { "Prev Save Slot ", 1<<25 }, - { "Next Save Slot ", 1<<24 }, - { "Switch Renderer ", 1<<26 }, - { "Fast forward ", 1<<22 }, - { "Pico Next page ", 1<<21 }, - { "Pico Prev page ", 1<<20 }, - { "Pico Switch input", 1<<19 }, - { NULL, 0 } -}; - -static void kc_sel_loop(void) -{ - int menu_sel = 5, menu_sel_max = 5; - unsigned long inp = 0; - menu_id selected_id; - - while (1) - { - draw_kc_sel(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0); - selected_id = me_index2id(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, menu_sel); - if (inp & (PBTN_LEFT|PBTN_RIGHT)) // multi choise - me_process(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0); - if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - if (inp & PBTN_CIRCLE) { - int is_6button = PicoIn.opt & POPT_6BTN_PAD; - switch (selected_id) { - case MA_CTRL_PLAYER1: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 0); return; - case MA_CTRL_PLAYER2: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 1); return; - case MA_CTRL_EMU: key_config_loop(emuctrl_actions, - sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return; - case MA_CTRL_DONE: if (!rom_loaded) emu_WriteConfig(0); return; - default: return; - } - } - if (inp & PBTN_X) return; - } -} - - -// --------- sega/mega cd options ---------- - -menu_entry cdopt_entries[] = -{ - { NULL, MB_NONE, MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1, 0 }, - { NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 }, - { NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 }, - { "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, ¤tConfig.EmuOpt, 0x0400, 0, 0, 1, 1 }, - { "CDDA audio", MB_ONOFF, MA_CDOPT_CDDA, &PicoIn.opt, 0x0800, 0, 0, 1, 1 }, - { "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoIn.opt, 0x0400, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1, 1 }, - { "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoIn.opt, 0x8000, 0, 0, 1, 1 }, - { "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoIn.opt, 0x1000, 0, 0, 1, 1 }, - { "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoIn.opt, 0x2000, 0, 0, 1, 1 }, - { "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1, 0 }, -}; - -#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0])) -const int cdopt_entry_count = CDOPT_ENTRY_COUNT; - - -struct bios_names_t -{ - char us[32], eu[32], jp[32]; -}; - -static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param) -{ - struct bios_names_t *bios_names = param; - char ra_buff[16]; - - switch (entry->id) - { - case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break; - case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break; - case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break; - case MA_CDOPT_READAHEAD: - if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2); - else strcpy(ra_buff, " OFF"); - text_out16(x, y, "ReadAhead buffer %s", ra_buff); + if (inp & (PBTN_MOK|PBTN_MBACK)) break; - default:break; - } -} - -static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names) -{ - int tl_x = 80+25, tl_y = 16+60; - menu_id selected_id; - char ra_buff[16]; - - if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2); - else strcpy(ra_buff, " OFF"); - - menu_draw_begin(); - - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246); - - me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names); - - selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel); - if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) || - (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) || - (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND"))) - text_out16(tl_x, 250, "Press start to test selected BIOS"); - - menu_draw_end(); -} - -static void cd_menu_loop_options(void) -{ - static int menu_sel = 0; - int menu_sel_max = 10; - unsigned long inp = 0; - struct bios_names_t bios_names; - menu_id selected_id; - char *bios, *p; - - if (emu_findBios(4, &bios)) { // US - for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); - if (*p == '/') p++; - strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0; - } else strcpy(bios_names.us, "NOT FOUND"); - - if (emu_findBios(8, &bios)) { // EU - for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); - if (*p == '/') p++; - strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0; - } else strcpy(bios_names.eu, "NOT FOUND"); - - if (emu_findBios(1, &bios)) { // JP - for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); - if (*p == '/') p++; - strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0; - } else strcpy(bios_names.jp, "NOT FOUND"); - - menuErrorMsg[0] = 0; - - for (;;) - { - draw_cd_menu_options(menu_sel, &bios_names); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE|PBTN_START, 0); - if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel); - if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise - if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0) && - selected_id == MA_CDOPT_READAHEAD) { - if (inp & PBTN_LEFT) { - PicoCDBuffers >>= 1; - if (PicoCDBuffers < 2) PicoCDBuffers = 0; - } else { - if (PicoCDBuffers < 2) PicoCDBuffers = 2; - else PicoCDBuffers <<= 1; - if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M - } - } - } - if (inp & PBTN_CIRCLE) // toggleable options - if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) && - selected_id == MA_CDOPT_DONE) { - return; - } - if (inp & PBTN_START) { - switch (selected_id) { // BIOS testers - case MA_CDOPT_TESTBIOS_USA: - if (emu_findBios(4, &bios)) { // test US - strcpy(romFileName, bios); - engineState = PGS_ReloadRom; - return; - } - break; - case MA_CDOPT_TESTBIOS_EUR: - if (emu_findBios(8, &bios)) { // test EU - strcpy(romFileName, bios); - engineState = PGS_ReloadRom; - return; - } - break; - case MA_CDOPT_TESTBIOS_JAP: - if (emu_findBios(1, &bios)) { // test JP - strcpy(romFileName, bios); - engineState = PGS_ReloadRom; - return; - } - break; - default: - break; - } - } - if (inp & PBTN_X) return; - } -} - -// --------- display options ---------- - -menu_entry opt3_entries[] = -{ - { NULL, MB_NONE, MA_OPT3_SCALE, NULL, 0, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_OPT3_HSCALE32, NULL, 0, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_OPT3_HSCALE40, NULL, 0, 0, 0, 1, 1 }, - { NULL, MB_ONOFF, MA_OPT3_FILTERING, ¤tConfig.scaling, 1, 0, 0, 1, 1 }, - { NULL, MB_RANGE, MA_OPT3_GAMMAA, ¤tConfig.gamma, 0, -4, 16, 1, 1 }, - { NULL, MB_RANGE, MA_OPT3_BLACKLVL, ¤tConfig.gamma2, 0, 0, 2, 1, 1 }, - { NULL, MB_NONE, MA_OPT3_VSYNC, NULL, 0, 0, 0, 1, 1 }, - { "Set to unscaled centered", MB_NONE, MA_OPT3_PRES_NOSCALE, NULL, 0, 0, 0, 1, 0 }, - { "Set to 4:3 scaled", MB_NONE, MA_OPT3_PRES_SCALE43, NULL, 0, 0, 0, 1, 0 }, - { "Set to fullscreen", MB_NONE, MA_OPT3_PRES_FULLSCR, NULL, 0, 0, 0, 1, 0 }, - { "done", MB_NONE, MA_OPT3_DONE, NULL, 0, 0, 0, 1, 0 }, -}; - -#define OPT3_ENTRY_COUNT (sizeof(opt3_entries) / sizeof(opt3_entries[0])) -const int opt3_entry_count = OPT3_ENTRY_COUNT; - - -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; - case MA_OPT3_GAMMAA: - text_out16(x, y, "Gamma adjustment %2i", currentConfig.gamma); - break; - case MA_OPT3_BLACKLVL: - text_out16(x, y, "Black level %2i", currentConfig.gamma2); - break; - case MA_OPT3_VSYNC: { - char *val = " never"; - if (currentConfig.EmuOpt & 0x2000) - val = (currentConfig.EmuOpt & 0x10000) ? "sometimes" : " always"; - text_out16(x, y, "Wait for vsync (slow) %s", val); - break; - } - default: break; - } -} - -static void menu_opt3_preview(int is_32col) -{ - void *oldstate = NULL; - - if (!rom_loaded || ((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; - ret = uncompress((Bytef *)bg_buffer, &outsize, bgdata, insize); - if (ret == 0) - { - if (rom_loaded) 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_uncached(psp_screen, 0, 512*272*2/4); - emu_forcedFrame(0); - menu_prepare_bg(1, 0); - - if (oldstate) restore_oldstate(oldstate); -} - -static void draw_dispmenu_options(int menu_sel) -{ - int tl_x = 80, tl_y = 16+50; - - menu_draw_begin(); - - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 316); - - 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 = (Pico.video.reg[12]&1)^1; - 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 = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0); - if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if (inp & PBTN_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 & (PBTN_LEFT|PBTN_RIGHT)) // multi choise - { - float *setting = NULL; - int tmp; - me_process(opt3_entries, OPT3_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0); - switch (selected_id) { - case MA_OPT3_SCALE: setting = ¤tConfig.scale; break; - case MA_OPT3_HSCALE40: setting = ¤tConfig.hscale40; is_32col = 0; break; - case MA_OPT3_HSCALE32: setting = ¤tConfig.hscale32; is_32col = 1; break; - case MA_OPT3_FILTERING: - case MA_OPT3_GAMMAA: - case MA_OPT3_BLACKLVL: menu_opt3_preview(is_32col); break; - case MA_OPT3_VSYNC: - tmp = ((currentConfig.EmuOpt>>13)&1) | ((currentConfig.EmuOpt>>15)&2); - tmp = (inp & PBTN_LEFT) ? (tmp>>1) : ((tmp<<1)|1); - if (tmp > 3) tmp = 3; - currentConfig.EmuOpt &= ~0x12000; - currentConfig.EmuOpt |= ((tmp&2)<<15) | ((tmp&1)<<13); - break; - default: break; - } - if (setting != NULL) { - while ((inp = psp_pad_read(0)) & (PBTN_LEFT|PBTN_RIGHT)) { - *setting += (inp & PBTN_LEFT) ? -0.01 : 0.01; - if (*setting <= 0) *setting = 0.01; - menu_opt3_preview(is_32col); - draw_dispmenu_options(menu_sel); // will wait vsync - } - } - } - if (inp & PBTN_CIRCLE) { // 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_SCALE43: - currentConfig.scale = 1.20; - currentConfig.hscale40 = 1.00; - currentConfig.hscale32 = 1.25; - 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 & PBTN_X) return; - } -} - - -// --------- advanced options ---------- - -menu_entry opt2_entries[] = -{ - { "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoIn.opt, 0x40000, 0, 0, 1, 1 }, - { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoIn.opt, 0x00004, 0, 0, 1, 1 }, - { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoIn.opt, 0x00001, 0, 0, 1, 1 }, - { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496, &PicoIn.opt, 0x00002, 0, 0, 1, 1 }, - { "Emulate YM2413 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2413, &PicoIn.opt, 0x00020, 0, 0, 1, 1 }, - { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, ¤tConfig.EmuOpt, 0x00008, 0, 0, 1, 1 }, - { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, ¤tConfig.EmuOpt, 0x00020, 0, 0, 1, 1 }, - { "Status line in main menu", MB_ONOFF, MA_OPT2_STATUS_LINE, ¤tConfig.EmuOpt, 0x20000, 0, 0, 1, 1 }, - { "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoIn.opt, 0x80000, 0, 0, 1, 1 }, - { "Disable frame limiter", MB_ONOFF, MA_OPT2_NO_FRAME_LIMIT, ¤tConfig.EmuOpt, 0x40000, 0, 0, 1, 1 }, - { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 }, -}; - -#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0])) -const int opt2_entry_count = OPT2_ENTRY_COUNT; - - -static void draw_amenu_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(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, NULL, NULL); - - menu_draw_end(); -} - -static void amenu_loop_options(void) -{ - static int menu_sel = 0; - int menu_sel_max; - unsigned long inp = 0; - menu_id selected_id; - - menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1; - - for(;;) - { - draw_amenu_options(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0); - if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel); - if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise - if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0) && - selected_id == MA_OPT2_GAMMA) { - // TODO? - } - } - if (inp & PBTN_CIRCLE) { // toggleable options - if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) && - selected_id == MA_OPT2_DONE) { - return; - } - } - if (inp & PBTN_X) return; - } -} - -// -------------- options -------------- - - -menu_entry opt_entries[] = -{ - { NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1, 1 }, - { "Accurate sprites", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoIn.opt, 0x080, 0, 0, 0, 1 }, - { "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, ¤tConfig.EmuOpt, 0x0002, 0, 0, 1, 1 }, - { NULL, MB_RANGE, MA_OPT_FRAMESKIP, ¤tConfig.Frameskip, 0, -1, 16, 1, 1 }, - { "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, ¤tConfig.EmuOpt, 0x0004, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_OPT_REGION, NULL, 0, 0, 0, 1, 1 }, - { "Use SRAM/BRAM savestates", MB_ONOFF, MA_OPT_SRAM_STATES, ¤tConfig.EmuOpt, 0x0001, 0, 0, 1, 1 }, - { NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1, 1 }, - { "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1, 1 }, - { NULL, MB_NONE, MA_OPT_CPU_CLOCKS, NULL, 0, 0, 0, 1, 1 }, - { "[Display options]", MB_NONE, MA_OPT_DISP_OPTS, NULL, 0, 0, 0, 1, 0 }, - { "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1, 0 }, - { "[Advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1, 0 }, - { NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1, 0 }, - { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1, 0 }, - { NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1, 0 }, -}; - -#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0])) -const int opt_entry_count = OPT_ENTRY_COUNT; - - -static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param) -{ - char *str, str24[24]; - - switch (entry->id) - { - case MA_OPT_RENDERER: - if (PicoIn.opt & 0x10) - str = "fast"; - else if (currentConfig.EmuOpt & 0x80) - str = "accurate"; - else - str = " 8bit accurate"; // n/a - text_out16(x, y, "Renderer: %s", str); - break; - case MA_OPT_FRAMESKIP: - if (currentConfig.Frameskip < 0) - strcpy(str24, "Auto"); - else sprintf(str24, "%i", currentConfig.Frameskip); - text_out16(x, y, "Frameskip %s", str24); - break; - case MA_OPT_SOUND_QUALITY: - str = (PicoIn.opt&0x08)?"stereo":"mono"; - text_out16(x, y, "Sound Quality: %5iHz %s", PicoIn.sndRate, str); - break; - case MA_OPT_REGION: - text_out16(x, y, "Region: %s", me_region_name(PicoIn.regionOverride, PicoIn.autoRgnOrder)); - break; - case MA_OPT_CONFIRM_STATES: - switch ((currentConfig.EmuOpt >> 9) & 5) { - default: str = "OFF"; break; - case 1: str = "writes"; break; - case 4: str = "loads"; break; - case 5: str = "both"; break; - } - text_out16(x, y, "Confirm savestate %s", str); - break; - case MA_OPT_CPU_CLOCKS: - text_out16(x, y, "CPU/bus clock %3i/%3iMHz", currentConfig.CPUclock, currentConfig.CPUclock/2); - break; - case MA_OPT_SAVECFG: - str24[0] = 0; - if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot); - text_out16(x, y, "Save cfg as default%s", str24); - break; - case MA_OPT_LOADCFG: - text_out16(x, y, "Load cfg from profile %i", config_slot); - break; - default: - lprintf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id); - break; - } -} - - -static void draw_menu_options(int menu_sel) -{ - int tl_x = 80+25, tl_y = 16+24; - menu_draw_begin(); - - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284); - - me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL); - - menu_draw_end(); -} - -static int sndrate_prevnext(int rate, int dir) -{ - int i, rates[] = { 11025, 22050, 44100 }; - - for (i = 0; i < 5; i++) - if (rates[i] == rate) break; - - i += dir ? 1 : -1; - if (i > 2) return dir ? 44100 : 22050; - if (i < 0) return dir ? 22050 : 11025; - return rates[i]; -} - -static void region_prevnext(int right) -{ - // jp_ntsc=1, jp_pal=2, usa=4, eu=8 - static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 }; - int i; - if (right) { - if (!PicoIn.regionOverride) { - for (i = 0; i < 6; i++) - if (rgn_orders[i] == PicoIn.autoRgnOrder) break; - if (i < 5) PicoIn.autoRgnOrder = rgn_orders[i+1]; - else PicoIn.regionOverride=1; + if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) { + if (g_layer_cx < 0) g_layer_cx = 0; + if (g_layer_cx > 640) g_layer_cx = 640; + if (g_layer_cy < 0) g_layer_cy = 0; + if (g_layer_cy > 420) g_layer_cy = 420; + if (g_layer_cw < 160) g_layer_cw = 160; + if (g_layer_ch < 60) g_layer_ch = 60; + if (g_layer_cx + g_layer_cw > 800) + g_layer_cw = 800 - g_layer_cx; + if (g_layer_cy + g_layer_ch > 480) + g_layer_ch = 480 - g_layer_cy; + pnd_setup_layer(1, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch); } - else PicoIn.regionOverride<<=1; - if (PicoIn.regionOverride > 8) PicoIn.regionOverride = 8; - } else { - if (!PicoIn.regionOverride) { - for (i = 0; i < 6; i++) - if (rgn_orders[i] == PicoIn.autoRgnOrder) break; - if (i > 0) PicoIn.autoRgnOrder = rgn_orders[i-1]; - } - else PicoIn.regionOverride>>=1; - } -} - -static void menu_options_save(void) -{ - if (PicoIn.regionOverride) { - // force setting possibly changed.. - Pico.m.pal = (PicoIn.regionOverride == 2 || PicoIn.regionOverride == 8) ? 1 : 0; - } - if (!(PicoIn.opt & POPT_6BTN_PAD)) { - // unbind XYZ MODE, just in case - unbind_action(0xf00); } -} -static int menu_loop_options(void) -{ - static int menu_sel = 0; - int menu_sel_max, ret; - unsigned long inp = 0; - menu_id selected_id; + pnd_setup_layer(0, g_layer_cx, g_layer_cy, g_layer_cw, g_layer_ch); - me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded); - me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current); - menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1; - if (menu_sel > menu_sel_max) menu_sel = menu_sel_max; - - while (1) - { - draw_menu_options(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_X|PBTN_CIRCLE, 0); - if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel); - if (inp & (PBTN_LEFT|PBTN_RIGHT)) { // multi choise - if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0)) { - switch (selected_id) { - case MA_OPT_RENDERER: - if ((PicoIn.opt & 0x10) || !(currentConfig.EmuOpt & 0x80)) { - PicoIn.opt &= ~0x10; - currentConfig.EmuOpt |= 0x80; - } else { - PicoIn.opt |= 0x10; - currentConfig.EmuOpt &= ~0x80; - } - break; - case MA_OPT_SOUND_QUALITY: - PicoIn.sndRate = sndrate_prevnext(PicoIn.sndRate, inp & PBTN_RIGHT); - break; - case MA_OPT_REGION: - region_prevnext(inp & PBTN_RIGHT); - break; - case MA_OPT_CONFIRM_STATES: { - int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2); - n += (inp & PBTN_LEFT) ? -1 : 1; - if (n < 0) n = 0; else if (n > 3) n = 3; - n |= n << 1; n &= ~2; - currentConfig.EmuOpt &= ~0xa00; - currentConfig.EmuOpt |= n << 9; - break; - } - case MA_OPT_SAVE_SLOT: - if (inp & PBTN_RIGHT) { - state_slot++; if (state_slot > 9) state_slot = 0; - } else {state_slot--; if (state_slot < 0) state_slot = 9; - } - break; - case MA_OPT_CPU_CLOCKS: - while ((inp = psp_pad_read(0)) & (PBTN_LEFT|PBTN_RIGHT)) { - currentConfig.CPUclock += (inp & PBTN_LEFT) ? -1 : 1; - if (currentConfig.CPUclock < 19) currentConfig.CPUclock = 19; - if (currentConfig.CPUclock > 333) currentConfig.CPUclock = 333; - draw_menu_options(menu_sel); // will wait vsync - } - break; - case MA_OPT_SAVECFG: - case MA_OPT_SAVECFG_GAME: - case MA_OPT_LOADCFG: - config_slot += (inp&PBTN_RIGHT) ? 1 : -1; - if (config_slot > 9) config_slot = 0; - if (config_slot < 0) config_slot = 9; - me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current); - menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1; - if (menu_sel > menu_sel_max) menu_sel = menu_sel_max; - break; - default: - //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id); - break; - } - } - } - if (inp & PBTN_CIRCLE) { - if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1)) - { - 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) - return 0; // test BIOS - break; - case MA_OPT_ADV_OPTS: - amenu_loop_options(); - break; - case MA_OPT_SAVECFG: // done (update and write) - menu_options_save(); - if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved"); - else strcpy(menuErrorMsg, "failed to write config"); - return 1; - case MA_OPT_SAVECFG_GAME: // done (update and write for current game) - menu_options_save(); - if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved"); - else strcpy(menuErrorMsg, "failed to write config"); - return 1; - case MA_OPT_LOADCFG: - ret = emu_ReadConfig(1, 1); - if (!ret) ret = emu_ReadConfig(0, 1); - if (ret) strcpy(menuErrorMsg, "config loaded"); - else strcpy(menuErrorMsg, "failed to load config"); - return 1; - default: - //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id); - break; - } - } - } - if(inp & PBTN_X) { - menu_options_save(); - return 0; // done (update, no write) - } - } + return 0; } +#endif -// -------------- credits -------------- - -static void draw_menu_credits(void) -{ - int tl_x = 80+15, tl_y = 16+64, y; - menu_draw_begin(); - - text_out16(tl_x, 16+20, "PicoDrive v" VERSION " (c) notaz, 2006-2008"); - - y = tl_y; - text_out16(tl_x, y, "Credits:"); - text_out16(tl_x, (y+=10), "fDave: base code of PicoDrive"); - text_out16(tl_x, (y+=10), "Chui: Fame/C"); - text_out16(tl_x, (y+=10), "NJ: CZ80"); - text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores"); - text_out16(tl_x, (y+=10), "ps2dev.org people: PSP SDK/code"); - text_out16(tl_x, (y+=10), "ketchupgun: skin design"); - - text_out16(tl_x, (y+=20), "special thanks (for docs, ideas):"); - text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,"); - text_out16(tl_x, (y+=10), " Stephane Dallongeville,"); - text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,"); - text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe"); - - menu_draw_end(); -} - - -// -------------- root menu -------------- - -menu_entry main_entries[] = -{ - { "Resume game", MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0 }, - { "Save State", MB_NONE, MA_MAIN_SAVE_STATE, NULL, 0, 0, 0, 0 }, - { "Load State", MB_NONE, MA_MAIN_LOAD_STATE, NULL, 0, 0, 0, 0 }, - { "Reset game", MB_NONE, MA_MAIN_RESET_GAME, NULL, 0, 0, 0, 0 }, - { "Load new ROM/ISO", MB_NONE, MA_MAIN_LOAD_ROM, NULL, 0, 0, 0, 1 }, - { "Change options", MB_NONE, MA_MAIN_OPTIONS, NULL, 0, 0, 0, 1 }, - { "Configure controls", MB_NONE, MA_MAIN_CONTROLS, NULL, 0, 0, 0, 1 }, - { "Credits", MB_NONE, MA_MAIN_CREDITS, NULL, 0, 0, 0, 1 }, - { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES, NULL, 0, 0, 0, 0 }, - { "Exit", MB_NONE, MA_MAIN_EXIT, NULL, 0, 0, 0, 1 } -}; - -#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0])) - -static void draw_menu_root(int menu_sel) -{ - const int tl_x = 86+70, tl_y = 16+70; - char *stat = NULL; - - menu_draw_begin(); - - if ((currentConfig.EmuOpt&0x20000) && (stat = psp_get_status_line())) - text_out16(287, 12, "%s", stat); - - text_out16(tl_x, 48, "PicoDrive v" VERSION); - - menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146); - - me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL); - - // error - if (menuErrorMsg[0]) - text_out16(10, 252, menuErrorMsg); - menu_draw_end(); -} - - -static void menu_loop_root(void) -{ - static int menu_sel = 0; - int ret, menu_sel_max; - unsigned long inp = 0; - - me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded); - me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_loaded); - me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE, rom_loaded); - me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME, rom_loaded); - me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES, PicoPatches != NULL); - - menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1; - if (menu_sel > menu_sel_max) menu_sel = menu_sel_max; - - // mp3 errors? - if (mp3_last_error != 0) { - if (mp3_last_error == -1) - sprintf(menuErrorMsg, "Unsupported mp3 format, use 44kHz stereo"); - else sprintf(menuErrorMsg, "mp3 init failed, code %08x", mp3_last_error); - mp3_last_error = 0; - } - - /* make sure action buttons are not pressed on entering menu */ - draw_menu_root(menu_sel); - - while (psp_pad_read(1) & (PBTN_X|PBTN_CIRCLE|PBTN_SELECT)) psp_msleep(50); - - for (;;) - { - draw_menu_root(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_X|PBTN_CIRCLE|PBTN_SELECT|PBTN_L|PBTN_R, 0); - if(inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if(inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - if((inp & (PBTN_L|PBTN_R)) == (PBTN_L|PBTN_R)) debug_menu_loop(); - if( inp & (PBTN_SELECT|PBTN_X)) { - if (rom_loaded) { - while (psp_pad_read(1) & (PBTN_SELECT|PBTN_X)) psp_msleep(50); // wait until released - engineState = PGS_Running; - break; - } - } - if(inp & PBTN_CIRCLE) { - menuErrorMsg[0] = 0; // clear error msg - switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel)) - { - case MA_MAIN_RESUME_GAME: - if (rom_loaded) { - while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50); - engineState = PGS_Running; - return; - } - break; - case MA_MAIN_SAVE_STATE: - if (rom_loaded) { - if(savestate_menu_loop(0)) - continue; - engineState = PGS_Running; - return; - } - break; - case MA_MAIN_LOAD_STATE: - if (rom_loaded) { - if(savestate_menu_loop(1)) - continue; - while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50); - engineState = PGS_Running; - return; - } - break; - case MA_MAIN_RESET_GAME: - if (rom_loaded) { - emu_ResetGame(); - while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50); - engineState = PGS_Running; - return; - } - break; - case MA_MAIN_LOAD_ROM: - { - char curr_path[PATH_MAX], *selfname; - FILE *tstf; - if ( (tstf = fopen(loadedRomFName, "rb")) ) - { - fclose(tstf); - strcpy(curr_path, loadedRomFName); - } - else - getcwd(curr_path, PATH_MAX); - selfname = romsel_loop(curr_path); - if (selfname) { - lprintf("selected file: %s\n", selfname); - engineState = PGS_ReloadRom; - return; - } - break; - } - case MA_MAIN_OPTIONS: - ret = menu_loop_options(); - if (ret == 1) continue; // status update - if (engineState == PGS_ReloadRom) - return; // BIOS test - break; - case MA_MAIN_CONTROLS: - kc_sel_loop(); - break; - case MA_MAIN_CREDITS: - draw_menu_credits(); - psp_msleep(500); - inp = 0; - while (!(inp & (PBTN_X|PBTN_CIRCLE))) - inp = in_menu_wait(PBTN_X|PBTN_CIRCLE, 0); - break; - case MA_MAIN_EXIT: - engineState = PGS_Quit; - return; - case MA_MAIN_PATCHES: - if (rom_loaded && PicoPatches) { - patches_menu_loop(); - PicoPatchApply(); - strcpy(menuErrorMsg, "Patches applied"); - continue; - } - break; - default: - lprintf("%s: something unknown selected\n", __FUNCTION__); - break; - } - } - } -} - -void menu_darken_bg(void *dst, const void *src, int pixels, int darker) -{ - unsigned int *dest = dst; - const unsigned int *srce = src; - pixels /= 2; - if (darker) - { - while (pixels--) - { - unsigned int p = *srce++; - *dest++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3); - } - } - else - { - while (pixels--) - { - unsigned int p = *srce++; - *dest++ = (p&0xf79ef79e)>>1; - } - } -} - -static void menu_prepare_bg(int use_game_bg, int use_fg) -{ - if (use_game_bg) - { - // darken the active framebuffer - unsigned short *dst = bg_buffer; - unsigned short *src = use_fg ? psp_video_get_active_fb() : psp_screen; - int i; - for (i = 272; i > 0; i--, dst += 480, src += 512) - menu_darken_bg(dst, src, 480, 1); - //memset32_uncached((int *)(bg_buffer + 480*264), 0, 480*8*2/4); - } - else - { - // should really only happen once, on startup.. - memset32_uncached((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_loaded, 1); - - menu_draw_begin(); - menu_draw_end(); -} - - -void menu_loop(void) -{ - menu_gfx_prepare(); - - menu_loop_root(); - - menuErrorMsg[0] = 0; -} - - -// --------- CD tray close menu ---------- - -static void draw_menu_tray(int menu_sel) -{ - int tl_x = 70, tl_y = 90, y; - - menu_draw_begin(); - - text_out16(tl_x, 20, "The unit is about to"); - text_out16(tl_x, 30, "close the CD tray."); - - y = tl_y; - text_out16(tl_x, y, "Load new CD image"); - text_out16(tl_x, (y+=10), "Insert nothing"); - - // draw cursor - text_out16(tl_x - 16, tl_y + menu_sel*10, ">"); - // error - if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg); - menu_draw_end(); -} - - -int menu_loop_tray(void) -{ - int menu_sel = 0, menu_sel_max = 1; - unsigned long inp = 0; - char curr_path[PATH_MAX], *selfname; - FILE *tstf; - - menu_gfx_prepare(); - - if ( (tstf = fopen(loadedRomFName, "rb")) ) - { - fclose(tstf); - strcpy(curr_path, loadedRomFName); - } - else - { - getcwd(curr_path, PATH_MAX); - } - - /* make sure action buttons are not pressed on entering menu */ - draw_menu_tray(menu_sel); - while (psp_pad_read(1) & PBTN_CIRCLE) psp_msleep(50); - - for (;;) - { - draw_menu_tray(menu_sel); - inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_CIRCLE, 0); - if(inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; } - if(inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } - if(inp & PBTN_CIRCLE) { - switch (menu_sel) { - case 0: // select image - selfname = romsel_loop(curr_path); - if (selfname) { - int ret = -1; - cd_img_type cd_type; - cd_type = emu_cdCheck(NULL, romFileName); - if (cd_type != CIT_NOT_CD) - ret = Insert_CD(romFileName, cd_type); - if (ret != 0) { - sprintf(menuErrorMsg, "Load failed, invalid CD image?"); - lprintf("%s\n", menuErrorMsg); - continue; - } - engineState = PGS_RestartRun; - return 1; - } - break; - case 1: // insert nothing - engineState = PGS_RestartRun; - return 0; - } - } - menuErrorMsg[0] = 0; // clear error msg - } -} +#define MENU_OPTIONS_GFX \ + mee_enum ("Scaler", MA_OPT_SCALING, currentConfig.scaling, \ + men_scaler), \ + mee_onoff ("Vsync", MA_OPT3_VSYNC, currentConfig.EmuOpt, EOPT_VSYNC), \ + /* mee_cust_h ("Setup custom scaler", MA_NONE, menu_loop_cscaler, NULL, h_cscaler), \*/ +#define MENU_OPTIONS_ADV diff --git a/platform/psp/mp3.c b/platform/psp/mp3.c index eac13ffd..5ec82066 100644 --- a/platform/psp/mp3.c +++ b/platform/psp/mp3.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -136,19 +135,11 @@ static int read_next_frame(int which_buffer) static SceUID load_start_module(const char *prxname) { - SceUID mod, mod1; - int status, ret; + SceUID mod; mod = pspSdkLoadStartModule(prxname, PSP_MEMORY_PARTITION_KERNEL); if (mod < 0) { lprintf("failed to load %s (%08x), trying kuKernelLoadModule\n", prxname, mod); - mod1 = kuKernelLoadModule(prxname, 0, NULL); - if (mod1 < 0) lprintf("kuKernelLoadModule failed with %08x\n", mod1); - else { - ret = sceKernelStartModule(mod1, 0, NULL, &status, 0); - if (ret < 0) lprintf("sceKernelStartModule failed with %08x\n", ret); - else mod = mod1; - } } return mod; } @@ -467,7 +458,7 @@ int mp3_get_offset(void) // 0-1023 int cdda_on; cdda_on = (PicoIn.AHW & PAHW_MCD) && (PicoIn.opt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) && - (Pico_mcd->scd.Status_CDC & 1) && mp3_handle >= 0; + /* TODO (Pico_mcd->scd.Status_CDC & 1) &&*/ mp3_handle >= 0; if (cdda_on) { offs1024 = mp3_src_pos << 7; diff --git a/platform/psp/plat.c b/platform/psp/plat.c new file mode 100644 index 00000000..9b2277fe --- /dev/null +++ b/platform/psp/plat.c @@ -0,0 +1,314 @@ +/* + * Platform interface functions for PSP picodrive frontend + * + * (C) 2020 kub + */ +#include +#include +#include +#include + +#include "../common/emu.h" +#include "../libpicofe/menu.h" +#include "../libpicofe/plat.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "psp.h" +#include "emu.h" +#include "asm_utils.h" + +#include + +/* graphics buffer management in VRAM: + * - VRAM_FB0, VRAM_FB1 frame buffers + * - VRAM_DEPTH Z buffer (unused) + * - VRAM_BUF0, VRAM_BUF1 emulator render buffers + * Emulator screen output is using the MD screen resolutions and is rendered + * to VRAM_BUFx and subsequently projected (that is, scaled and blitted) into + * the associated frame buffer (in PSP output resolution). Additional emulator + * output is then directly rendered to that frame buffer. + * The emulator menu is rendered directly into the frame buffers, using the + * native PSP resolution. + * Menu background uses native resolution and is copied and shaded from a frame + * buffer, or read in from a file if no emulator screen output is present. + */ + +/* System level intialization */ +int plat_target_init(void) +{ + psp_init(); + + /* buffer resolutions */ + g_menuscreen_w = 480, g_menuscreen_h = 272, g_menuscreen_pp = 512; + g_screen_width = 328, g_screen_height = 256, g_screen_ppitch = 512; + g_menubg_src_w = 480, g_menubg_src_h = 272, g_menubg_src_pp = 512; + + /* buffer settings for menu display on startup */ + g_screen_ptr = VRAM_CACHED_STUFF + (psp_screen - VRAM_FB0); + g_menuscreen_ptr = psp_screen; + g_menubg_ptr = malloc(512*272*2); + + return 0; +} + +/* System level deinitialization */ +void plat_target_finish(void) +{ + psp_finish(); +} + +/* display a completed frame buffer and prepare a new render buffer */ +void plat_video_flip(void) +{ + g_menubg_src_ptr = psp_screen; + psp_video_flip(currentConfig.EmuOpt & EOPT_VSYNC); + g_screen_ptr = VRAM_CACHED_STUFF + (psp_screen - VRAM_FB0); + plat_video_set_buffer(g_screen_ptr); +} + +/* wait for start of vertical blanking */ +void plat_video_wait_vsync(void) +{ + sceDisplayWaitVblankStart(); +} + +/* switch from emulation display to menu display */ +void plat_video_menu_enter(int is_rom_loaded) +{ +} + +/* start rendering a menu screen */ +void plat_video_menu_begin(void) +{ + g_menuscreen_ptr = psp_screen; +} + +/* display a completed menu screen */ +void plat_video_menu_end(void) +{ + plat_video_wait_vsync(); + plat_video_flip(); +} + +/* terminate menu display */ +void plat_video_menu_leave(void) +{ +} + +/* Preliminary initialization needed at program start */ +void plat_early_init(void) +{ +} + +/* base directory for configuration and save files */ +int plat_get_root_dir(char *dst, int len) +{ + if (len > 0) *dst = 0; + return 0; +} + +/* base directory for emulator resources */ +int plat_get_skin_dir(char *dst, int len) +{ + if (len > 0) *dst = 0; + return 0; +} + +/* check if path is a directory */ +int plat_is_dir(const char *path) +{ + SceIoStat st; + int ret = sceIoGetstat(path, &st); + return (ret >= 0 && (st.st_mode & FIO_S_IFDIR)); +} + +/* current time in ms */ +unsigned int plat_get_ticks_ms(void) +{ + /* approximate /= 1000 */ + unsigned long long v64; + v64 = (unsigned long long)plat_get_ticks_us() * 4294968; + return v64 >> 32; +} + +/* current time in us */ +unsigned int plat_get_ticks_us(void) +{ + return sceKernelGetSystemTimeLow(); +} + +/* sleep for some time in ms */ +void plat_sleep_ms(int ms) +{ + psp_msleep(ms); +} + +/* sleep for some time in us */ +void plat_wait_till_us(unsigned int us_to) +{ + unsigned int tval; + int diff; + + tval = sceKernelGetSystemTimeLow(); + diff = (int)us_to - (int)tval; + if (diff >= 512 && diff < 100*1024) + sceKernelDelayThread(diff); +} + +/* wait until some event occurs, or timeout */ +int plat_wait_event(int *fds_hnds, int count, int timeout_ms) +{ + return 0; // unused +} + +/* memory mapping functions */ +void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed) +{ + return malloc(size); +} + +void *plat_mremap(void *ptr, size_t oldsize, size_t newsize) +{ + return realloc(ptr, newsize); +} + +void plat_munmap(void *ptr, size_t size) +{ + free(ptr); +} + +void *plat_mem_get_for_drc(size_t size) +{ + return NULL; +} + +int plat_mem_set_exec(void *ptr, size_t size) +{ + return 0; +} + +/* get current CPU clock */ +static int plat_cpu_clock_get(void) +{ + return scePowerGetCpuClockFrequencyInt(); +} + +/* set CPU clock */ +static int plat_cpu_clock_set(int clock) +{ + if (clock < 33) clock = 33; + if (clock > 333) clock = 333; + + return scePowerSetClockFrequency(clock, clock, clock/2); +} + +/* get battery state in percent */ +static int plat_bat_capacity_get(void) +{ + return scePowerGetBatteryLifePercent(); +} + +struct plat_target plat_target = { + .cpu_clock_get = plat_cpu_clock_get, + .cpu_clock_set = plat_cpu_clock_set, + .bat_capacity_get = plat_bat_capacity_get, +// .gamma_set = plat_gamma_set, +// .hwfilter_set = plat_hwfilter_set, +// .hwfilters = plat_hwfilters, +}; + + +/* replacement libc stuff */ + +int alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +int scandir(const char *dir, struct dirent ***namelist_out, + int(*filter)(const struct dirent *), + int(*compar)(const struct dirent **, const struct dirent **)) +{ + int ret = -1, dir_uid = -1, name_alloc = 4, name_count = 0; + struct dirent **namelist = NULL, *ent; + SceIoDirent sce_ent; + + namelist = malloc(sizeof(*namelist) * name_alloc); + if (namelist == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } + + // try to read first.. + dir_uid = sceIoDopen(dir); + if (dir_uid >= 0) + { + /* it is very important to clear SceIoDirent to be passed to sceIoDread(), */ + /* or else it may crash, probably misinterpreting something in it. */ + memset(&sce_ent, 0, sizeof(sce_ent)); + ret = sceIoDread(dir_uid, &sce_ent); + if (ret < 0) + { + lprintf("sceIoDread(\"%s\") failed with %i\n", dir, ret); + goto fail; + } + } + else + lprintf("sceIoDopen(\"%s\") failed with %i\n", dir, dir_uid); + + while (ret > 0) + { + ent = malloc(sizeof(*ent)); + if (ent == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } + ent->d_stat = sce_ent.d_stat; + ent->d_stat.st_attr &= FIO_SO_IFMT; // serves as d_type + strncpy(ent->d_name, sce_ent.d_name, sizeof(ent->d_name)); + ent->d_name[sizeof(ent->d_name)-1] = 0; + if (filter == NULL || filter(ent)) + namelist[name_count++] = ent; + else free(ent); + + if (name_count >= name_alloc) + { + void *tmp; + name_alloc *= 2; + tmp = realloc(namelist, sizeof(*namelist) * name_alloc); + if (tmp == NULL) { lprintf("%s:%i: OOM\n", __FILE__, __LINE__); goto fail; } + namelist = tmp; + } + + memset(&sce_ent, 0, sizeof(sce_ent)); + ret = sceIoDread(dir_uid, &sce_ent); + } + + // sort + if (compar != NULL && name_count > 3) + qsort(&namelist[2], name_count - 2, sizeof(namelist[0]), (int (*)()) compar); + + // all done. + ret = name_count; + *namelist_out = namelist; + goto end; + +fail: + if (namelist != NULL) + { + while (name_count--) + free(namelist[name_count]); + free(namelist); + } +end: + if (dir_uid >= 0) sceIoDclose(dir_uid); + return ret; +} + +int _flush_cache (char *addr, const int size, const int op) +{ + sceKernelDcacheWritebackRange(addr, size); + sceKernelIcacheInvalidateRange(addr, size); + return 0; +} diff --git a/platform/psp/psp.c b/platform/psp/psp.c index a5bfe3a6..3273ad31 100644 --- a/platform/psp/psp.c +++ b/platform/psp/psp.c @@ -21,24 +21,26 @@ #include "psp.h" #include "emu.h" + #include +#include "../common/emu.h" #include "../common/version.h" -extern int pico_main(void); +extern int pico_main(int argc, char *argv[]); #ifndef FW15 -PSP_MODULE_INFO("PicoDrive", 0, 1, 51); +PSP_MODULE_INFO("PicoDrive", 0, 1, 97); PSP_HEAP_SIZE_MAX(); -int main() { return pico_main(); } /* just a wrapper */ +int main(int argc, char *argv[]) { return pico_main(argc, argv); } /* just a wrapper */ #else -PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 51); +PSP_MODULE_INFO("PicoDrive", 0x1000, 1, 97); PSP_MAIN_THREAD_ATTR(0); -int main() +int main(int argc, char *argv[]) { SceUID thid; @@ -47,7 +49,7 @@ int main() thid = sceKernelCreateThread("pico_main", (SceKernelThreadEntry) pico_main, 32, 0x2000, PSP_THREAD_ATTR_USER, NULL); if (thid >= 0) - sceKernelStartThread(thid, 0, 0); + sceKernelStartThread(thid, argc, argv); #ifndef GCOV sceKernelExitDeleteThread(0); #else @@ -133,7 +135,7 @@ void psp_init(void) lprintf("\n%s\n", "PicoDrive v" VERSION " " __DATE__ " " __TIME__); lprintf("running on %08x kernel\n", sceKernelDevkitVersion()), lprintf("entered psp_init, threadId %08x, priority %i\n", main_thread_id, - sceKernelGetThreadCurrentPriority()); + sceKernelGetThreadCurrentPriority()); thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, NULL); if (thid >= 0) @@ -153,8 +155,8 @@ void psp_init(void) sceGuStart(GU_DIRECT, guCmdList); 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((void *)VRAMOFFS_DEPTH, 512); + sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT); sceGuOffset(2048 - (480 / 2), 2048 - (272 / 2)); sceGuViewport(2048, 2048, 480, 272); sceGuDepthRange(0xc350, 0x2710); @@ -226,11 +228,11 @@ unsigned int psp_pad_read(int blocking) buttons = pad.Buttons; // analog.. - buttons &= ~(PBTN_NUB_UP|PBTN_NUB_DOWN|PBTN_NUB_LEFT|PBTN_NUB_RIGHT); - if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_LEFT; - if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_RIGHT; - if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PBTN_NUB_UP; - if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PBTN_NUB_DOWN; + buttons &= ~(PSP_NUB_UP|PSP_NUB_DOWN|PSP_NUB_LEFT|PSP_NUB_RIGHT); + if (pad.Lx < 128 - ANALOG_DEADZONE) buttons |= PSP_NUB_LEFT; + if (pad.Lx > 128 + ANALOG_DEADZONE) buttons |= PSP_NUB_RIGHT; + if (pad.Ly < 128 - ANALOG_DEADZONE) buttons |= PSP_NUB_UP; + if (pad.Ly > 128 + ANALOG_DEADZONE) buttons |= PSP_NUB_DOWN; return buttons; } diff --git a/platform/psp/psp.h b/platform/psp/psp.h index 7067f051..f33971c1 100644 --- a/platform/psp/psp.h +++ b/platform/psp/psp.h @@ -50,24 +50,9 @@ char *psp_get_status_line(void); void psp_wait_suspend(void); void psp_resume_suspend(void); -/* shorter btn names */ -#define PBTN_UP PSP_CTRL_UP -#define PBTN_LEFT PSP_CTRL_LEFT -#define PBTN_RIGHT PSP_CTRL_RIGHT -#define PBTN_DOWN PSP_CTRL_DOWN -#define PBTN_L PSP_CTRL_LTRIGGER -#define PBTN_R PSP_CTRL_RTRIGGER -#define PBTN_TRIANGLE PSP_CTRL_TRIANGLE -#define PBTN_CIRCLE PSP_CTRL_CIRCLE -#define PBTN_X PSP_CTRL_CROSS -#define PBTN_SQUARE PSP_CTRL_SQUARE -#define PBTN_SELECT PSP_CTRL_SELECT -#define PBTN_START PSP_CTRL_START -#define PBTN_NOTE PSP_CTRL_NOTE // doesn't seem to work? - -/* fake 'nub' btns */ -#define PBTN_NUB_UP (1 << 28) -#define PBTN_NUB_RIGHT (1 << 29) -#define PBTN_NUB_DOWN (1 << 30) -#define PBTN_NUB_LEFT (1 << 31) +/* fake 'nub' btns, mapped to the 4 unused upper bits of ctrl buttons */ +#define PSP_NUB_UP (1 << 28) +#define PSP_NUB_RIGHT (1 << 29) +#define PSP_NUB_DOWN (1 << 30) +#define PSP_NUB_LEFT (1 << 31) -- 2.39.5