some skinning capabilities

git-svn-id: file:///home/notaz/opt/svn/PicoDrive@225 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
notaz 2007-08-24 20:47:28 +00:00
parent a9b3ffd3cc
commit a12e011623
21 changed files with 606 additions and 252 deletions

View file

@ -653,6 +653,13 @@ int PicoFrame(void)
return 0; return 0;
} }
void PicoFrameDrawOnly(void)
{
int y;
PicoFrameStart();
for (y=0;y<224;y++) PicoLine(y);
}
// callback to output message from emu // callback to output message from emu
void (*PicoMessage)(const char *msg)=NULL; void (*PicoMessage)(const char *msg)=NULL;

View file

@ -41,6 +41,7 @@ int PicoInit(void);
void PicoExit(void); void PicoExit(void);
int PicoReset(int hard); int PicoReset(int hard);
int PicoFrame(void); int PicoFrame(void);
void PicoFrameDrawOnly(void);
extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU extern int PicoPad[2]; // Joypads, format is MXYZ SACB RLDU
extern void (*PicoWriteSound)(int len); // called once per frame at the best time to send sound buffer (PsndOut) to hardware extern void (*PicoWriteSound)(int len); // called once per frame at the best time to send sound buffer (PsndOut) to hardware
extern void (*PicoMessage)(const char *msg); // callback to output text message from emu extern void (*PicoMessage)(const char *msg); // callback to output text message from emu

View file

@ -415,10 +415,10 @@ void YM2612Init_940(int baseclock, int rate)
fp = fopen(binpath, "rb"); fp = fopen(binpath, "rb");
if(!fp) if(!fp)
{ {
memset(gp2x_screen, 0, 320*240); memset(gp2x_screen, 0, 320*240*2);
gp2x_text_out8(10, 100, "failed to open required file:"); text_out16(10, 100, "failed to open required file:");
gp2x_text_out8(10, 110, CODE940_FILE); text_out16(10, 110, CODE940_FILE);
gp2x_video_flip(); gp2x_video_flip2();
printf("failed to open %s\n", binpath); printf("failed to open %s\n", binpath);
exit(1); exit(1);
} }

View file

@ -47,7 +47,7 @@ LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy OBJCOPY = $(CROSS)objcopy
# frontend # frontend
OBJS += main.o menu.o fonts.o gp2x.o usbjoy.o emu.o squidgehack.o asmutils.o cpuctrl.o OBJS += main.o menu.o fonts.o gp2x.o usbjoy.o emu.o squidgehack.o asmutils.o cpuctrl.o readpng.o
# 940 core control # 940 core control
OBJS += 940ctl.o OBJS += 940ctl.o
# Pico # Pico
@ -121,7 +121,7 @@ all: PicoDrive.gpe
PicoDrive.gpe : $(OBJS) helix/helix_mp3.a PicoDrive.gpe : $(OBJS) helix/helix_mp3.a
@echo $@ @echo $@
@$(GCC) -o $@ $(COPT) $^ -lm -Wl,-Map=PicoDrive.map @$(GCC) -o $@ $(COPT) $^ -lm -lpng -Wl,-Map=PicoDrive.map
ifeq ($(DEBUG),) ifeq ($(DEBUG),)
@$(STRIP) $@ @$(STRIP) $@
endif endif
@ -212,6 +212,7 @@ endif
rel: PicoDrive.gpe code940/pico940.bin ../readme.txt config.txt PicoDrive.man.txt PicoDrive.png rel: PicoDrive.gpe code940/pico940.bin ../readme.txt config.txt PicoDrive.man.txt PicoDrive.png
zip -9 -j ../../PicoDrive_$(VER).zip $^ mmuhack.o zip -9 -j ../../PicoDrive_$(VER).zip $^ mmuhack.o
zip -9 PicoDrive_$(VER).zip skin
code940/code940.bin: code940/code940.bin:
make -C code940/ make -C code940/

View file

@ -10,5 +10,5 @@ void vidCpyM2_40col(void *dest, void *src);
void vidCpyM2_32col(void *dest, void *src); void vidCpyM2_32col(void *dest, void *src);
void vidCpyM2_32col_nobord(void *dest, void *src); void vidCpyM2_32col_nobord(void *dest, void *src);
void spend_cycles(int c); // utility void spend_cycles(int c); // utility
void flushcache(void); void flushcache(void *beginning_addr, void *end_addr, unsigned int flags);

View file

@ -211,7 +211,6 @@ spend_cycles:
bx lr bx lr
@ test
.global flushcache .global flushcache
flushcache: flushcache:

View file

@ -20,6 +20,7 @@
#include "menu.h" #include "menu.h"
#include "asmutils.h" #include "asmutils.h"
#include "cpuctrl.h" #include "cpuctrl.h"
#include "fonts.h"
#include <Pico/PicoInt.h> #include <Pico/PicoInt.h>
#include <Pico/Patch.h> #include <Pico/Patch.h>
@ -634,6 +635,53 @@ void emu_Deinit(void)
set_gamma(100, 0); set_gamma(100, 0);
} }
static void text_out8_builtin(int x, int y, const char *text)
{
int i,l,len=strlen(text);
unsigned char *screen = (unsigned char *)gp2x_screen + x + y*320;
/* always using built-in font */
for (i = 0; i < len; i++)
{
for (l=0;l<8;l++)
{
unsigned char fd = fontdata8x8[((text[i])*8)+l];
if (fd&0x80) screen[l*320+0]=0xf0;
if (fd&0x40) screen[l*320+1]=0xf0;
if (fd&0x20) screen[l*320+2]=0xf0;
if (fd&0x10) screen[l*320+3]=0xf0;
if (fd&0x08) screen[l*320+4]=0xf0;
if (fd&0x04) screen[l*320+5]=0xf0;
if (fd&0x02) screen[l*320+6]=0xf0;
if (fd&0x01) screen[l*320+7]=0xf0;
}
screen += 8;
}
}
static void text_out16_builtin(int x, int y, const char *text)
{
int i,l,len=strlen(text);
unsigned short *screen = (unsigned short *)gp2x_screen + x + y*320;
for (i = 0; i < len; i++)
{
for (l=0;l<8;l++)
{
unsigned char fd = fontdata8x8[((text[i])*8)+l];
if(fd&0x80) screen[l*320+0]=0xffff;
if(fd&0x40) screen[l*320+1]=0xffff;
if(fd&0x20) screen[l*320+2]=0xffff;
if(fd&0x10) screen[l*320+3]=0xffff;
if(fd&0x08) screen[l*320+4]=0xffff;
if(fd&0x04) screen[l*320+5]=0xffff;
if(fd&0x02) screen[l*320+6]=0xffff;
if(fd&0x01) screen[l*320+7]=0xffff;
}
screen += 8;
}
}
void osd_text(int x, int y, const char *text) void osd_text(int x, int y, const char *text)
{ {
@ -647,7 +695,7 @@ void osd_text(int x, int y, const char *text)
p = (int *) ((unsigned char *) gp2x_screen+x+320*(y+h)); p = (int *) ((unsigned char *) gp2x_screen+x+320*(y+h));
for (i = len; i; i--, p++) *p = 0xe0e0e0e0; for (i = len; i; i--, p++) *p = 0xe0e0e0e0;
} }
gp2x_text_out8_2(x, y, text, 0xf0); text_out8_builtin(x, y, text);
} else { } else {
int *p, i, h; int *p, i, h;
x &= ~1; // align x x &= ~1; // align x
@ -656,7 +704,7 @@ void osd_text(int x, int y, const char *text)
p = (int *) ((unsigned short *) gp2x_screen+x+320*(y+h)); p = (int *) ((unsigned short *) gp2x_screen+x+320*(y+h));
for (i = len; i; i--, p++) *p = (*p>>2)&0x39e7; for (i = len; i; i--, p++) *p = (*p>>2)&0x39e7;
} }
gp2x_text_out15(x, y, text); text_out16_builtin(x, y, text);
} }
} }
@ -794,7 +842,7 @@ static void vidResetMode(void)
if (PicoOpt&0x10) { if (PicoOpt&0x10) {
gp2x_video_changemode(8); gp2x_video_changemode(8);
} else if (currentConfig.EmuOpt&0x80) { } else if (currentConfig.EmuOpt&0x80) {
gp2x_video_changemode(15); gp2x_video_changemode(16);
PicoDrawSetColorFormat(1); PicoDrawSetColorFormat(1);
PicoScan = EmuScan16; PicoScan = EmuScan16;
PicoScan(0, 0); PicoScan(0, 0);
@ -1045,10 +1093,20 @@ static void SkipFrame(int do_audio)
void emu_forced_frame(void) void emu_forced_frame(void)
{ {
int po_old = PicoOpt; int po_old = PicoOpt;
int eo_old = currentConfig.EmuOpt;
PicoOpt |= 0x10; PicoOpt &= ~0x0010;
PicoFrameFull(); PicoOpt |= 0x4080; // soft_scale | acc_sprites
currentConfig.EmuOpt |= 0x80;
//vidResetMode();
PicoDrawSetColorFormat(1);
PicoScan = EmuScan16;
PicoScan(0, 0);
Pico.m.dirtyPal = 1;
PicoFrameDrawOnly();
/*
if (!(Pico.video.reg[12]&1)) { if (!(Pico.video.reg[12]&1)) {
vidCpyM2 = vidCpyM2_32col; vidCpyM2 = vidCpyM2_32col;
clearArea(1); clearArea(1);
@ -1057,8 +1115,9 @@ void emu_forced_frame(void)
vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8); vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8);
vidConvCpyRGB32(localPal, Pico.cram, 0x40); vidConvCpyRGB32(localPal, Pico.cram, 0x40);
gp2x_video_setpalette(localPal, 0x40); gp2x_video_setpalette(localPal, 0x40);
*/
PicoOpt = po_old; PicoOpt = po_old;
currentConfig.EmuOpt = eo_old;
} }
static void simpleWait(int thissec, int lim_time) static void simpleWait(int thissec, int lim_time)
@ -1375,12 +1434,9 @@ if (Pico.m.frame_count == 31563) {
SRam.changed = 0; SRam.changed = 0;
} }
// if in 16bit mode, generate 8it image for menu background // if in 8bit mode, generate 16bit image for menu background
if (!(PicoOpt&0x10) && (currentConfig.EmuOpt&0x80)) if ((PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80))
emu_forced_frame(); emu_forced_frame();
// for menu bg
gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);
} }

View file

@ -157,6 +157,15 @@ void gp2x_video_wait_vsync(void)
} }
void gp2x_video_flush_cache(void)
{
// since we are using the mmu hack, we must flush the cache first
// (the params are most likely wrong, but they seem to work somehow)
//flushcache(addr, addr + 320*240*2, 0);
flushcache(gp2x_screen, (char *)gp2x_screen + 320*240*2, 0);
}
void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len) void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)
{ {
char *dst; char *dst;
@ -184,9 +193,7 @@ void gp2x_memset_all_buffers(int offset, int byte, int len)
void gp2x_pd_clone_buffer2(void) void gp2x_pd_clone_buffer2(void)
{ {
memcpy(gp2x_screen, gp2x_screens[2], 320*240); memcpy(gp2x_screen, gp2x_screens[2], 320*240*2);
memset(gp2x_screen, 0xe0, 320*8);
memset(gp2x_screen + 320*232, 0xe0, 320*8);
} }

View file

@ -14,6 +14,7 @@ void gp2x_video_changemode2(int bpp);
void gp2x_video_setpalette(int *pal, int len); void gp2x_video_setpalette(int *pal, int len);
void gp2x_video_RGB_setscaling(int ln_offs, int W, int H); void gp2x_video_RGB_setscaling(int ln_offs, int W, int H);
void gp2x_video_wait_vsync(void); void gp2x_video_wait_vsync(void);
void gp2x_video_flush_cache(void);
void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len); void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len);
void gp2x_memcpy_all_buffers(void *data, int offset, int len); void gp2x_memcpy_all_buffers(void *data, int offset, int len);
void gp2x_memset_all_buffers(int offset, int byte, int len); void gp2x_memset_all_buffers(int offset, int byte, int len);

View file

@ -97,6 +97,7 @@ int main(int argc, char *argv[])
} }
sharedmem_init(); sharedmem_init();
emu_Init(); emu_Init();
menu_init();
engineState = PGS_Menu; engineState = PGS_Menu;

View file

@ -16,6 +16,7 @@
#include "fonts.h" #include "fonts.h"
#include "usbjoy.h" #include "usbjoy.h"
#include "asmutils.h" #include "asmutils.h"
#include "readpng.h"
#include "version.h" #include "version.h"
#include <Pico/PicoInt.h> #include <Pico/PicoInt.h>
@ -32,66 +33,71 @@ extern int mmuhack_status;
extern int state_slot; extern int state_slot;
extern int config_slot, config_slot_current; extern int config_slot, config_slot_current;
static unsigned char menu_font_data[10240];
static char *gp2xKeyNames[] = { static char *gp2xKeyNames[] = {
"UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???", "UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???",
"START", "SELECT", "L", "R", "A", "B", "X", "Y", "START", "SELECT", "L", "R", "A", "B", "X", "Y",
"???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP", "???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP",
"???", "???", "???", "PUSH", "???", "???", "???", "???" "???", "???", "???", "PUSH", "???", "???", "???", "???"
}; };
static int menu_text_color = 0xffff; // default to white
static int menu_sel_color = -1; // disabled
char menuErrorMsg[40] = {0, }; char menuErrorMsg[40] = {0, };
static void menu_darken_bg(void *dst, int pixels);
static void menu_prepare_bg(int use_game_bg);
static void gp2x_text(unsigned char *screen, int x, int y, const char *text, int color) // draws text to current bbp16 screen
static void text_out16_(int x, int y, const char *text, int color)
{ {
int i,l; int i, l, u, tr, tg, tb, len;
unsigned short *dest = (unsigned short *)gp2x_screen + x + y*320;
tr = (color & 0xf800) >> 8;
tg = (color & 0x07e0) >> 3;
tb = (color & 0x001f) << 3;
screen = screen + x + y*320; if (text == (void *)1)
for (i = 0; i < strlen(text); i++)
{ {
for (l=0;l<8;l++) // selector symbol
text = "";
len = 1;
}
else
len = strlen(text);
for (i = 0; i < len; i++)
{
unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;
unsigned short *dst = dest;
for (l = 0; l < 10; l++, dst += 320-8)
{ {
if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=color; for (u = 8/2; u > 0; u--, src++)
if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=color; {
if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=color; int c, r, g, b;
if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=color; c = *src >> 4;
if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=color; r = (*dst & 0xf800) >> 8;
if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=color; g = (*dst & 0x07e0) >> 3;
if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=color; b = (*dst & 0x001f) << 3;
if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=color; r = (c^0xf)*r/15 + c*tr/15;
g = (c^0xf)*g/15 + c*tg/15;
b = (c^0xf)*b/15 + c*tb/15;
*dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);
c = *src & 0xf;
r = (*dst & 0xf800) >> 8;
g = (*dst & 0x07e0) >> 3;
b = (*dst & 0x001f) << 3;
r = (c^0xf)*r/15 + c*tr/15;
g = (c^0xf)*g/15 + c*tg/15;
b = (c^0xf)*b/15 + c*tb/15;
*dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);
}
} }
screen += 8; dest += 8;
} }
} }
// draws white text to current bbp15 screen void text_out16(int x, int y, const char *texto, ...)
void gp2x_text_out15(int x, int y, const char *text)
{
int i,l;
unsigned short *screen = gp2x_screen;
screen = screen + x + y*320;
for (i = 0; i < strlen(text); i++)
{
for (l=0;l<8;l++)
{
if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=0xffff;
if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=0xffff;
}
screen += 8;
}
}
void gp2x_text_out8(int x, int y, const char *texto, ...)
{ {
va_list args; va_list args;
char buffer[512]; char buffer[512];
@ -100,31 +106,15 @@ void gp2x_text_out8(int x, int y, const char *texto, ...)
vsprintf(buffer,texto,args); vsprintf(buffer,texto,args);
va_end(args); va_end(args);
gp2x_text(gp2x_screen,x,y,buffer,0xf0); text_out16_(x,y,buffer,menu_text_color);
} }
void gp2x_text_out8_2(int x, int y, const char *texto, int color) static void smalltext_out16(int x, int y, const char *texto, int color)
{
gp2x_text(gp2x_screen, x, y, texto, color);
}
void gp2x_text_out8_lim(int x, int y, const char *texto, int max)
{
char buffer[320/8+1];
strncpy(buffer, texto, 320/8);
if (max > 320/8) max = 320/8;
if (max < 0) max = 0;
buffer[max] = 0;
gp2x_text(gp2x_screen,x,y,buffer,0xf0);
}
static void gp2x_smalltext8(int x, int y, const char *texto)
{ {
int i; int i;
unsigned char *src, *dst; unsigned char *src;
unsigned short *dst;
for (i = 0;; i++, x += 6) for (i = 0;; i++, x += 6)
{ {
@ -134,14 +124,14 @@ static void gp2x_smalltext8(int x, int y, const char *texto)
if (!c) break; if (!c) break;
src = fontdata6x8[c]; src = fontdata6x8[c];
dst = (unsigned char *)gp2x_screen + x + y*320; dst = (unsigned short *)gp2x_screen + x + y*320;
while (h--) while (h--)
{ {
int w = 0x20; int w = 0x20;
while (w) while (w)
{ {
if( *src & w ) *dst = 0xf0; if( *src & w ) *dst = color;
dst++; dst++;
w>>=1; w>>=1;
} }
@ -152,7 +142,7 @@ static void gp2x_smalltext8(int x, int y, const char *texto)
} }
} }
static void gp2x_smalltext8_lim(int x, int y, const char *texto, int max) static void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)
{ {
char buffer[320/6+1]; char buffer[320/6+1];
@ -161,7 +151,33 @@ static void gp2x_smalltext8_lim(int x, int y, const char *texto, int max)
if (max < 0) max = 0; if (max < 0) max = 0;
buffer[max] = 0; buffer[max] = 0;
gp2x_smalltext8(x, y, buffer); smalltext_out16(x, y, buffer, color);
}
static void draw_selection(int x, int y, int w)
{
int i, h;
unsigned short *dst, *dest;
text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);
if (menu_sel_color < 0) return; // no selection hilight
if (y > 0) y--;
dest = (unsigned short *)gp2x_screen + x + y*320 + 14;
for (h = 11; h > 0; h--)
{
dst = dest;
for (i = w; i > 0; i--)
*dst++ = menu_sel_color;
dest += 320;
}
}
static void menu_flip(void)
{
gp2x_video_flush_cache();
gp2x_video_flip2();
} }
@ -303,11 +319,11 @@ static void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_
y1 += 10; y1 += 10;
continue; continue;
} }
gp2x_text_out8(x, y1, entries[i].name); text_out16(x, y1, entries[i].name);
if (entries[i].beh == MB_ONOFF) if (entries[i].beh == MB_ONOFF)
gp2x_text_out8(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF"); text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");
else if (entries[i].beh == MB_RANGE) else if (entries[i].beh == MB_RANGE)
gp2x_text_out8(x + 27*8, y1, "%i", *(int *)entries[i].var); text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);
y1 += 10; y1 += 10;
} }
} }
@ -332,7 +348,73 @@ static int me_process(menu_entry *entries, int count, menu_id id, int is_next)
} }
static int parse_hex_color(char *buff)
{
char *endp = buff;
int t = (int) strtoul(buff, &endp, 16);
if (endp != buff) return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);
return -1;
}
void menu_init(void)
{
int c, l;
unsigned char *fd = menu_font_data;
char buff[256];
FILE *f;
// generate default font from fontdata8x8
memset(menu_font_data, 0, sizeof(menu_font_data));
for (c = 0; c < 256; c++)
{
for (l = 0; l < 8; l++)
{
unsigned char fd8x8 = fontdata8x8[c*8+l];
if (fd8x8&0x80) *fd |= 0xf0;
if (fd8x8&0x40) *fd |= 0x0f; fd++;
if (fd8x8&0x20) *fd |= 0xf0;
if (fd8x8&0x10) *fd |= 0x0f; fd++;
if (fd8x8&0x08) *fd |= 0xf0;
if (fd8x8&0x04) *fd |= 0x0f; fd++;
if (fd8x8&0x02) *fd |= 0xf0;
if (fd8x8&0x01) *fd |= 0x0f; fd++;
}
fd += 8*2/2; // 2 empty lines
}
// load custom font and selector (stored as 1st symbol in font table)
readpng(menu_font_data, "skin/font.png", READPNG_FONT);
memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'
readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);
// load custom colors
f = fopen("skin/skin.txt", "r");
if (f != NULL)
{
printf("found skin.txt\n");
while (!feof(f))
{
fgets(buff, sizeof(buff), f);
if (buff[0] == '#' || buff[0] == '/') continue; // comment
if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line
if (strncmp(buff, "text_color=", 11) == 0)
{
int tmp = parse_hex_color(buff+11);
if (tmp >= 0) menu_text_color = tmp;
else printf("skin.txt: parse error for text_color\n");
}
else if (strncmp(buff, "selection_color=", 16) == 0)
{
int tmp = parse_hex_color(buff+16);
if (tmp >= 0) menu_sel_color = tmp;
else printf("skin.txt: parse error for selection_color\n");
}
else
printf("skin.txt: parse error: %s\n", buff);
}
fclose(f);
}
}
static unsigned long inp_prev = 0; static unsigned long inp_prev = 0;
static int inp_prevjoy = 0; static int inp_prevjoy = 0;
@ -425,12 +507,12 @@ static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy)
static void load_progress_cb(int percent) static void load_progress_cb(int percent)
{ {
int ln, len = percent * 320 / 100; int ln, len = percent * 320 / 100;
unsigned char *dst = (unsigned char *)gp2x_screen + 320*20; unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;
if (len > 320) len = 320; if (len > 320) len = 320;
for (ln = 10; ln > 0; ln--, dst += 320) for (ln = 10; ln > 0; ln--, dst += 320)
memset(dst, 0xf0, len); memset(dst, 0xff, len*2);
gp2x_video_flip2(); menu_flip();
} }
void menu_romload_prepare(const char *rom_name) void menu_romload_prepare(const char *rom_name)
@ -438,23 +520,41 @@ void menu_romload_prepare(const char *rom_name)
const char *p = rom_name + strlen(rom_name); const char *p = rom_name + strlen(rom_name);
while (p > rom_name && *p != '/') p--; while (p > rom_name && *p != '/') p--;
gp2x_pd_clone_buffer2(); if (rom_data) gp2x_pd_clone_buffer2();
gp2x_smalltext8(1, 1, "Loading"); else memset(gp2x_screen, 0, 320*240*2);
gp2x_smalltext8_lim(1, 10, p, 53);
gp2x_memcpy_buffers(3, gp2x_screen, 0, 320*240); smalltext_out16(1, 1, "Loading", 0xffff);
gp2x_video_flip2(); smalltext_out16_lim(1, 10, p, 0xffff, 53);
gp2x_memcpy_buffers(3, gp2x_screen, 0, 320*240*2);
menu_flip();
PicoCartLoadProgressCB = load_progress_cb; PicoCartLoadProgressCB = load_progress_cb;
} }
void menu_romload_end(void) void menu_romload_end(void)
{ {
PicoCartLoadProgressCB = NULL; PicoCartLoadProgressCB = NULL;
gp2x_smalltext8(1, 30, "Starting emulation..."); smalltext_out16(1, 30, "Starting emulation...", 0xffff);
gp2x_video_flip2(); menu_flip();
} }
// -------------- ROM selector -------------- // -------------- ROM selector --------------
// rrrr rggg gggb bbbb
static unsigned short file2color(const char *fname)
{
const char *ext = fname + strlen(fname) - 3;
static const char *rom_exts[] = { "zip", "bin", "smd", "gen", "iso" };
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 0xbdff;
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 dirent **namelist, int n, int sel) static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)
{ {
int start, i, pos; int start, i, pos;
@ -462,23 +562,31 @@ static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)
start = 12 - sel; start = 12 - sel;
n--; // exclude current dir (".") n--; // exclude current dir (".")
gp2x_pd_clone_buffer2(); if (rom_data)
gp2x_pd_clone_buffer2();
else {
memset(gp2x_screen, 0, 320*240*2);
memset((char *)gp2x_screen + 320*120*2, 0xff, 320*8*2);
}
menu_darken_bg((char *)gp2x_screen + 320*120*2, 320*8);
if(start - 2 >= 0) if(start - 2 >= 0)
gp2x_smalltext8_lim(14, (start - 2)*10, curdir, 53-2); smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
pos = start + i; pos = start + i;
if (pos < 0) continue; if (pos < 0) continue;
if (pos > 23) break; if (pos > 23) break;
if (namelist[i+1]->d_type == DT_DIR) { if (namelist[i+1]->d_type == DT_DIR) {
gp2x_smalltext8_lim(14, pos*10, "/", 1); smalltext_out16_lim(14, pos*10, "/", 0xfff6, 1);
gp2x_smalltext8_lim(14+6, pos*10, namelist[i+1]->d_name, 53-3); smalltext_out16_lim(14+6, pos*10, namelist[i+1]->d_name, 0xfff6, 53-3);
} else { } else {
gp2x_smalltext8_lim(14, pos*10, namelist[i+1]->d_name, 53-2); unsigned short color = file2color(namelist[i+1]->d_name);
smalltext_out16_lim(14, pos*10, namelist[i+1]->d_name, color, 53-2);
} }
} }
gp2x_text_out8(5, 120, ">"); text_out16(5, 120, ">");
gp2x_video_flip2(); menu_flip();
} }
static int scandir_cmp(const void *p1, const void *p2) static int scandir_cmp(const void *p1, const void *p2)
@ -637,11 +745,11 @@ static void draw_debug(void)
while (*p && *p != '\n') p++; while (*p && *p != '\n') p++;
len = p - str; len = p - str;
if (len > 55) len = 55; if (len > 55) len = 55;
gp2x_smalltext8_lim(1, line*10, str, len); smalltext_out16_lim(1, line*10, str, 0xffff, len);
if (*p == 0) break; if (*p == 0) break;
p++; str = p; p++; str = p;
} }
gp2x_video_flip2(); menu_flip();
} }
static void debug_menu_loop(void) static void debug_menu_loop(void)
@ -654,7 +762,7 @@ static void debug_menu_loop(void)
static void draw_patchlist(int sel) static void draw_patchlist(int sel)
{ {
int start, i, pos; int start, i, pos, active;
start = 12 - sel; start = 12 - sel;
@ -664,14 +772,15 @@ static void draw_patchlist(int sel)
pos = start + i; pos = start + i;
if (pos < 0) continue; if (pos < 0) continue;
if (pos > 23) break; if (pos > 23) break;
gp2x_smalltext8_lim(14, pos*10, PicoPatches[i].active ? "ON " : "OFF", 3); active = PicoPatches[i].active;
gp2x_smalltext8_lim(14+6*4, pos*10, PicoPatches[i].name, 53-6); 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; pos = start + i;
if (pos < 24) gp2x_smalltext8_lim(14, pos*10, "done", 4); if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);
gp2x_text_out8(5, 120, ">"); text_out16(5, 120, ">");
gp2x_video_flip2(); menu_flip();
} }
@ -700,8 +809,6 @@ static void patches_menu_loop(void)
// ------------ savestate loader ------------ // ------------ savestate loader ------------
static void menu_prepare_bg(void);
static int state_slot_flags = 0; static int state_slot_flags = 0;
static void state_check_slots(void) static void state_check_slots(void)
@ -762,8 +869,7 @@ static void draw_savestate_bg(int slot)
} }
emu_forced_frame(); emu_forced_frame();
gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2); menu_prepare_bg(1);
menu_prepare_bg();
memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram)); memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));
memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram)); memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));
@ -780,20 +886,19 @@ static void draw_savestate_menu(int menu_sel, int is_loading)
draw_savestate_bg(menu_sel); draw_savestate_bg(menu_sel);
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
gp2x_text_out8(tl_x, 30, is_loading ? "Load state" : "Save state"); text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");
draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);
/* draw all 10 slots */ /* draw all 10 slots */
y = tl_y; y = tl_y;
for (i = 0; i < 10; i++, y+=10) for (i = 0; i < 10; i++, y+=10)
{ {
gp2x_text_out8(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free"); text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");
} }
gp2x_text_out8(tl_x, y, "back"); text_out16(tl_x, y, "back");
// draw cursor menu_flip();
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");
gp2x_video_flip2();
} }
static int savestate_menu_loop(int is_loading) static int savestate_menu_loop(int is_loading)
@ -918,33 +1023,32 @@ static void draw_key_config(const bind_action_t *opts, int opt_cnt, int player_i
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
if (player_idx >= 0) { if (player_idx >= 0) {
gp2x_text_out8(80, 20, "Player %i controls", player_idx + 1); text_out16(80, 20, "Player %i controls", player_idx + 1);
x = 100; x = 100;
} else { } else {
gp2x_text_out8(80, 20, "Emulator controls"); text_out16(80, 20, "Emulator controls");
x = 40; x = 40;
} }
draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130);
y = tl_y; y = tl_y;
for (i = 0; i < opt_cnt; i++, y+=10) for (i = 0; i < opt_cnt; i++, y+=10)
gp2x_text_out8(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask)); text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));
gp2x_text_out8(x, y, "Done"); text_out16(x, y, "Done");
// draw cursor
gp2x_text_out8(x - 16, tl_y + sel*10, ">");
if (sel < opt_cnt) { if (sel < opt_cnt) {
gp2x_text_out8(30, 190, "Press a button to bind/unbind"); text_out16(30, 180, "Press a button to bind/unbind");
gp2x_text_out8(30, 200, "Use SELECT to clear"); text_out16(30, 190, "Use SELECT to clear");
gp2x_text_out8(30, 210, "To bind UP/DOWN, hold SELECT"); text_out16(30, 200, "To bind UP/DOWN, hold SELECT");
gp2x_text_out8(30, 220, "Select \"Done\" to exit"); text_out16(30, 210, "Select \"Done\" to exit");
} else { } else {
gp2x_text_out8(30, 200, "Use Options -> Save cfg"); text_out16(30, 190, "Use Options -> Save cfg");
gp2x_text_out8(30, 210, "to save controls"); text_out16(30, 200, "to save controls");
gp2x_text_out8(30, 220, "Press B or X to exit"); text_out16(30, 210, "Press B or X to exit");
} }
gp2x_video_flip2(); menu_flip();
} }
static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_idx) static void key_config_loop(const bind_action_t *opts, int opt_cnt, int player_idx)
@ -1007,26 +1111,25 @@ static void draw_kc_sel(int menu_sel)
y = tl_y; y = tl_y;
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
gp2x_text_out8(tl_x, y, "Player 1"); draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);
gp2x_text_out8(tl_x, (y+=10), "Player 2");
gp2x_text_out8(tl_x, (y+=10), "Emulator controls");
gp2x_text_out8(tl_x, (y+=10), "Done");
// draw cursor text_out16(tl_x, y, "Player 1");
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); text_out16(tl_x, (y+=10), "Player 2");
text_out16(tl_x, (y+=10), "Emulator controls");
text_out16(tl_x, (y+=10), "Done");
tl_x = 25; tl_x = 25;
gp2x_text_out8(tl_x, (y=110), "USB joys detected:"); text_out16(tl_x, (y=110), "USB joys detected:");
if (num_of_joys > 0) { if (num_of_joys > 0) {
for (i = 0; i < num_of_joys; i++) { for (i = 0; i < num_of_joys; i++) {
strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0; strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;
gp2x_text_out8(tl_x, (y+=10), "%i: %s", i+1, joyname); text_out16(tl_x, (y+=10), "%i: %s", i+1, joyname);
} }
} else { } else {
gp2x_text_out8(tl_x, (y+=10), "none"); text_out16(tl_x, (y+=10), "none");
} }
gp2x_video_flip2(); menu_flip();
} }
@ -1052,13 +1155,13 @@ static bind_action_t ctrl_actions[] =
// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE" // "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"
static bind_action_t emuctrl_actions[] = static bind_action_t emuctrl_actions[] =
{ {
{ "Volume Down ", 1<<30 },
{ "Volume Up ", 1<<29 },
{ "Load State ", 1<<28 }, { "Load State ", 1<<28 },
{ "Save State ", 1<<27 }, { "Save State ", 1<<27 },
{ "Switch Renderer", 1<<26 },
{ "Prev Save Slot ", 1<<25 }, { "Prev Save Slot ", 1<<25 },
{ "Next Save Slot ", 1<<24 }, { "Next Save Slot ", 1<<24 },
{ "Switch Renderer", 1<<26 },
{ "Volume Down ", 1<<30 },
{ "Volume Up ", 1<<29 },
{ "Enter Menu ", 1<<23 }, { "Enter Menu ", 1<<23 },
}; };
@ -1121,13 +1224,13 @@ static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *pa
switch (entry->id) switch (entry->id)
{ {
case MA_CDOPT_TESTBIOS_USA: gp2x_text_out8(x, y, "USA BIOS: %s", bios_names->us); break; case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break;
case MA_CDOPT_TESTBIOS_EUR: gp2x_text_out8(x, y, "EUR BIOS: %s", bios_names->eu); break; case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break;
case MA_CDOPT_TESTBIOS_JAP: gp2x_text_out8(x, y, "JAP BIOS: %s", bios_names->jp); break; case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break;
case MA_CDOPT_READAHEAD: case MA_CDOPT_READAHEAD:
if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2); if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);
else strcpy(ra_buff, " OFF"); else strcpy(ra_buff, " OFF");
gp2x_text_out8(x, y, "ReadAhead buffer %s", ra_buff); text_out16(x, y, "ReadAhead buffer %s", ra_buff);
break; break;
default:break; default:break;
} }
@ -1144,18 +1247,17 @@ static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names); draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);
// draw cursor me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");
selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel); selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);
if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) || 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_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||
(selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND"))) (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))
gp2x_text_out8(tl_x, 220, "Press start to test selected BIOS"); text_out16(tl_x, 210, "Press start to test selected BIOS");
gp2x_video_flip2(); menu_flip();
} }
static void cd_menu_loop_options(void) static void cd_menu_loop_options(void)
@ -1263,9 +1365,9 @@ menu_entry opt2_entries[] =
static void menu_opt2_cust_draw(const menu_entry *entry, int x, int y, void *param) static void menu_opt2_cust_draw(const menu_entry *entry, int x, int y, void *param)
{ {
if (entry->id == MA_OPT2_GAMMA) if (entry->id == MA_OPT2_GAMMA)
gp2x_text_out8(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100); text_out16(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100);
else if (entry->id == MA_OPT2_SQUIDGEHACK) else if (entry->id == MA_OPT2_SQUIDGEHACK)
gp2x_text_out8(x, y, "squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)", text_out16(x, y, "squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)",
(currentConfig.EmuOpt&0x0010)?"ON":"OFF"); (currentConfig.EmuOpt&0x0010)?"ON":"OFF");
} }
@ -1276,12 +1378,11 @@ static void draw_amenu_options(int menu_sel)
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);
me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL); me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL);
// draw cursor menu_flip();
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");
gp2x_video_flip2();
} }
static void amenu_loop_options(void) static void amenu_loop_options(void)
@ -1388,7 +1489,7 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
str = "16bit accurate"; str = "16bit accurate";
else else
str = " 8bit accurate"; str = " 8bit accurate";
gp2x_text_out8(x, y, "Renderer: %s", str); text_out16(x, y, "Renderer: %s", str);
break; break;
case MA_OPT_SCALING: case MA_OPT_SCALING:
switch (currentConfig.scaling) { switch (currentConfig.scaling) {
@ -1397,20 +1498,20 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
case 2: str = "hw horiz. + vert."; break; case 2: str = "hw horiz. + vert."; break;
case 3: str = "sw horizontal"; break; case 3: str = "sw horizontal"; break;
} }
gp2x_text_out8(x, y, "Scaling: %s", str); text_out16(x, y, "Scaling: %s", str);
break; break;
case MA_OPT_FRAMESKIP: case MA_OPT_FRAMESKIP:
if (currentConfig.Frameskip < 0) if (currentConfig.Frameskip < 0)
strcpy(str24, "Auto"); strcpy(str24, "Auto");
else sprintf(str24, "%i", currentConfig.Frameskip); else sprintf(str24, "%i", currentConfig.Frameskip);
gp2x_text_out8(x, y, "Frameskip %s", str24); text_out16(x, y, "Frameskip %s", str24);
break; break;
case MA_OPT_SOUND_QUALITY: case MA_OPT_SOUND_QUALITY:
str = (currentConfig.PicoOpt&0x08)?"stereo":"mono"; str = (currentConfig.PicoOpt&0x08)?"stereo":"mono";
gp2x_text_out8(x, y, "Sound Quality: %5iHz %s", currentConfig.PsndRate, str); text_out16(x, y, "Sound Quality: %5iHz %s", currentConfig.PsndRate, str);
break; break;
case MA_OPT_REGION: case MA_OPT_REGION:
gp2x_text_out8(x, y, "Region: %s", region_name(currentConfig.PicoRegion)); text_out16(x, y, "Region: %s", region_name(currentConfig.PicoRegion));
break; break;
case MA_OPT_CONFIRM_STATES: case MA_OPT_CONFIRM_STATES:
switch ((currentConfig.EmuOpt >> 9) & 5) { switch ((currentConfig.EmuOpt >> 9) & 5) {
@ -1419,18 +1520,18 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
case 4: str = "loads"; break; case 4: str = "loads"; break;
case 5: str = "both"; break; case 5: str = "both"; break;
} }
gp2x_text_out8(x, y, "Confirm savestate %s", str); text_out16(x, y, "Confirm savestate %s", str);
break; break;
case MA_OPT_CPU_CLOCKS: case MA_OPT_CPU_CLOCKS:
gp2x_text_out8(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock); text_out16(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock);
break; break;
case MA_OPT_SAVECFG: case MA_OPT_SAVECFG:
str24[0] = 0; str24[0] = 0;
if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot); if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);
gp2x_text_out8(x, y, "Save cfg as default%s", str24); text_out16(x, y, "Save cfg as default%s", str24);
break; break;
case MA_OPT_LOADCFG: case MA_OPT_LOADCFG:
gp2x_text_out8(x, y, "Load cfg from profile %i", config_slot); text_out16(x, y, "Load cfg from profile %i", config_slot);
break; break;
default: default:
printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id); printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);
@ -1442,16 +1543,15 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
static void draw_menu_options(int menu_sel) static void draw_menu_options(int menu_sel)
{ {
int tl_x = 25, tl_y = 32; int tl_x = 25, tl_y = 24;
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
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); me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);
// draw cursor menu_flip();
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");
gp2x_video_flip2();
} }
static int sndrate_prevnext(int rate, int dir) static int sndrate_prevnext(int rate, int dir)
@ -1635,28 +1735,28 @@ static int menu_loop_options(void)
static void draw_menu_credits(void) static void draw_menu_credits(void)
{ {
int tl_x = 15, tl_y = 70, y; int tl_x = 15, tl_y = 64, y;
//memset(gp2x_screen, 0, 320*240);
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006,2007"); text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006,2007");
y = tl_y; y = tl_y;
gp2x_text_out8(tl_x, y, "Credits:"); text_out16(tl_x, y, "Credits:");
gp2x_text_out8(tl_x, (y+=10), "Dave: Cyclone 68000 core,"); text_out16(tl_x, (y+=10), "Dave: Cyclone 68000 core,");
gp2x_text_out8(tl_x, (y+=10), " base code of PicoDrive"); text_out16(tl_x, (y+=10), " base code of PicoDrive");
gp2x_text_out8(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core"); text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");
gp2x_text_out8(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores"); text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");
gp2x_text_out8(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs"); text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");
gp2x_text_out8(tl_x, (y+=10), "Stephane Dallongeville:"); text_out16(tl_x, (y+=10), "Stephane Dallongeville:");
gp2x_text_out8(tl_x, (y+=10), " opensource Gens"); text_out16(tl_x, (y+=10), " opensource Gens");
gp2x_text_out8(tl_x, (y+=10), "Haze: Genesis hw info"); text_out16(tl_x, (y+=10), "Haze: Genesis hw info");
gp2x_text_out8(tl_x, (y+=10), "rlyeh and others: minimal SDK"); text_out16(tl_x, (y+=10), "rlyeh and others: minimal SDK");
gp2x_text_out8(tl_x, (y+=10), "Squidge: squidgehack"); text_out16(tl_x, (y+=10), "Squidge: squidgehack");
gp2x_text_out8(tl_x, (y+=10), "Dzz: ARM940 sample"); text_out16(tl_x, (y+=10), "Dzz: ARM940 sample");
gp2x_text_out8(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick"); text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick");
gp2x_text_out8(tl_x, (y+=10), "craigix: GP2X hardware"); text_out16(tl_x, (y+=10), "craigix: GP2X hardware");
text_out16(tl_x, (y+=10), "ketch: skin design");
gp2x_video_flip2(); menu_flip();
} }
@ -1684,15 +1784,18 @@ static void draw_menu_root(int menu_sel)
gp2x_pd_clone_buffer2(); gp2x_pd_clone_buffer2();
gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION); text_out16(tl_x, 20, "PicoDrive v" VERSION);
draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);
me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL); me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);
// draw cursor
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");
// error // error
if (menuErrorMsg[0]) gp2x_text_out8(5, 226, menuErrorMsg); if (menuErrorMsg[0]) {
gp2x_video_flip2(); memset((char *)gp2x_screen + 320*224*2, 0, 320*16*2);
text_out16(5, 226, menuErrorMsg);
}
menu_flip();
} }
@ -1701,18 +1804,6 @@ static void menu_loop_root(void)
static int menu_sel = 0; static int menu_sel = 0;
int ret, menu_sel_max; int ret, menu_sel_max;
unsigned long inp = 0; unsigned long inp = 0;
char curr_path[PATH_MAX], *selfname;
FILE *tstf;
if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) )
{
fclose(tstf);
strcpy(curr_path, currentConfig.lastRomFile);
}
else
{
getcwd(curr_path, PATH_MAX);
}
me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_data != NULL); me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_data != NULL);
me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_data != NULL); me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_data != NULL);
@ -1775,12 +1866,24 @@ static void menu_loop_root(void)
} }
break; break;
case MA_MAIN_LOAD_ROM: case MA_MAIN_LOAD_ROM:
{
char curr_path[PATH_MAX], *selfname;
FILE *tstf;
if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) )
{
fclose(tstf);
strcpy(curr_path, currentConfig.lastRomFile);
}
else
getcwd(curr_path, PATH_MAX);
selfname = romsel_loop(curr_path); selfname = romsel_loop(curr_path);
if (selfname) { if (selfname) {
printf("selected file: %s\n", selfname); printf("selected file: %s\n", selfname);
engineState = PGS_ReloadRom; engineState = PGS_ReloadRom;
return;
} }
return; break;
}
case MA_MAIN_OPTIONS: case MA_MAIN_OPTIONS:
ret = menu_loop_options(); ret = menu_loop_options();
if (ret == 1) continue; // status update if (ret == 1) continue; // status update
@ -1815,31 +1918,45 @@ static void menu_loop_root(void)
} }
} }
static void menu_darken_bg(void *dst, int pixels)
static void menu_prepare_bg(void)
{ {
extern int localPal[0x100]; unsigned int *screen = dst;
int c, i; pixels /= 2;
while (pixels--)
// don't clear old palette just for fun (but make it dark) {
for (i = 0x100-1; i >= 0; i--) { unsigned int p = *screen;
c = localPal[i]; *screen = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);
localPal[i] = ((c >> 1) & 0x007f7f7f) - ((c >> 3) & 0x001f1f1f); screen++;
} }
localPal[0xe0] = 0x00000000; // reserved pixels for OSD }
localPal[0xf0] = 0x00ffffff;
gp2x_video_setpalette(localPal, 0x100); static void menu_prepare_bg(int use_game_bg)
{
if (use_game_bg)
{
// darken the active framebuffer
memset(gp2x_screen, 0, 320*8*2);
menu_darken_bg((char *)gp2x_screen + 320*8*2, 320*224);
memset((char *)gp2x_screen + 320*232*2, 0, 320*8*2);
}
else
{
// should really only happen once, on startup..
readpng(gp2x_screen, "skin/background.png", READPNG_BG);
}
// copy to buffer2
gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);
} }
static void menu_gfx_prepare(void) static void menu_gfx_prepare(void)
{ {
menu_prepare_bg(); menu_prepare_bg(rom_data != NULL);
// switch to 8bpp // switch to 16bpp
gp2x_video_changemode2(8); gp2x_video_changemode2(16);
gp2x_video_RGB_setscaling(0, 320, 240); gp2x_video_RGB_setscaling(0, 320, 240);
gp2x_video_flip2(); menu_flip();
} }
@ -1858,20 +1975,20 @@ void menu_loop(void)
static void draw_menu_tray(int menu_sel) static void draw_menu_tray(int menu_sel)
{ {
int tl_x = 70, tl_y = 90, y; int tl_x = 70, tl_y = 90, y;
memset(gp2x_screen, 0xe0, 320*240); memset(gp2x_screen, 0, 320*240*2);
gp2x_text_out8(tl_x, 20, "The unit is about to"); text_out16(tl_x, 20, "The unit is about to");
gp2x_text_out8(tl_x, 30, "close the CD tray."); text_out16(tl_x, 30, "close the CD tray.");
y = tl_y; y = tl_y;
gp2x_text_out8(tl_x, y, "Load new CD image"); text_out16(tl_x, y, "Load new CD image");
gp2x_text_out8(tl_x, (y+=10), "Insert nothing"); text_out16(tl_x, (y+=10), "Insert nothing");
// draw cursor // draw cursor
gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">"); text_out16(tl_x - 16, tl_y + menu_sel*10, ">");
// error // error
if (menuErrorMsg[0]) gp2x_text_out8(5, 226, menuErrorMsg); if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);
gp2x_video_flip2(); menu_flip();
} }

View file

@ -1,13 +1,12 @@
// (c) Copyright 2006 notaz, All rights reserved. // (c) Copyright 2006,2007 notaz, All rights reserved.
// Free for non-commercial use. // Free for non-commercial use.
// For commercial use, separate licencing terms must be obtained. // For commercial use, separate licencing terms must be obtained.
extern char menuErrorMsg[40]; extern char menuErrorMsg[40];
void gp2x_text_out8 (int x, int y, const char *texto, ...); void menu_init(void);
void gp2x_text_out15 (int x, int y, const char *text); void text_out16(int x, int y, const char *texto, ...);
void gp2x_text_out8_2(int x, int y, const char *texto, int color);
void menu_loop(void); void menu_loop(void);
int menu_loop_tray(void); int menu_loop_tray(void);
void menu_romload_prepare(const char *rom_name); void menu_romload_prepare(const char *rom_name);

143
platform/gp2x/readpng.c Normal file
View file

@ -0,0 +1,143 @@
#include <stdio.h>
#include <string.h>
#include <png.h>
#include "readpng.h"
void readpng(void *dest, const char *fname, readpng_what what)
{
FILE *fp;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_bytepp row_ptr = NULL;
if (dest == NULL || fname == NULL)
{
return;
}
fp = fopen(fname, "rb");
if (fp == NULL)
{
printf(__FILE__ ": failed to open: %s\n", fname);
return;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
printf(__FILE__ ": png_create_read_struct() failed\n");
fclose(fp);
return;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
printf(__FILE__ ": png_create_info_struct() failed\n");
goto done;
}
// Start reading
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_PACKING, NULL);
row_ptr = png_get_rows(png_ptr, info_ptr);
if (row_ptr == NULL)
{
printf(__FILE__ ": png_get_rows() failed\n");
goto done;
}
// printf("%s: %ix%i @ %ibpp\n", fname, (int)info_ptr->width, (int)info_ptr->height, info_ptr->pixel_depth);
switch (what)
{
case READPNG_BG:
{
int height, width, h;
unsigned short *dst = dest;
if (info_ptr->pixel_depth != 24)
{
printf(__FILE__ ": bg image uses %ibpp, needed 24bpp\n", info_ptr->pixel_depth);
break;
}
height = info_ptr->height;
if (height > 240) height = 240;
width = info_ptr->width;
if (width > 320) width = 320;
for (h = 0; h < height; h++)
{
unsigned char *src = row_ptr[h];
int len = width;
while (len--)
{
*dst++ = ((src[0]&0xf8)<<8) | ((src[1]&0xf8)<<3) | (src[2] >> 3);
src += 3;
}
dst += 320 - width;
}
break;
}
case READPNG_FONT:
{
int x, y, x1, y1;
unsigned char *dst = dest;
if (info_ptr->width != 128 || info_ptr->height != 160)
{
printf(__FILE__ ": unexpected font image size %ix%i, needed 128x160\n",
(int)info_ptr->width, (int)info_ptr->height);
break;
}
if (info_ptr->pixel_depth != 8)
{
printf(__FILE__ ": font image uses %ibpp, needed 8bpp\n", info_ptr->pixel_depth);
break;
}
for (y = 0; y < 16; y++)
{
for (x = 0; x < 16; x++)
{
for (y1 = 0; y1 < 10; y1++)
{
unsigned char *src = row_ptr[y*10 + y1] + x*8;
for (x1 = 8/2; x1 > 0; x1--, src+=2)
*dst++ = ((src[0]^0xff) & 0xf0) | ((src[1]^0xff) >> 4);
}
}
}
break;
}
case READPNG_SELECTOR:
{
int x1, y1;
unsigned char *dst = dest;
if (info_ptr->width != 8 || info_ptr->height != 10)
{
printf(__FILE__ ": unexpected selector image size %ix%i, needed 8x10\n",
(int)info_ptr->width, (int)info_ptr->height);
break;
}
if (info_ptr->pixel_depth != 8)
{
printf(__FILE__ ": selector image uses %ibpp, needed 8bpp\n", info_ptr->pixel_depth);
break;
}
for (y1 = 0; y1 < 10; y1++)
{
unsigned char *src = row_ptr[y1];
for (x1 = 8/2; x1 > 0; x1--, src+=2)
*dst++ = ((src[0]^0xff) & 0xf0) | ((src[1]^0xff) >> 4);
}
break;
}
}
done:
png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, (png_infopp)NULL);
fclose(fp);
}

10
platform/gp2x/readpng.h Normal file
View file

@ -0,0 +1,10 @@
typedef enum
{
READPNG_BG = 1,
READPNG_FONT,
READPNG_SELECTOR
}
readpng_what;
void readpng(void *dest, const char *fname, readpng_what what);

View file

@ -24,7 +24,8 @@ COPT += `pkg-config --cflags gthread-2.0`
LDFLAGS += `pkg-config --libs gthread-2.0` LDFLAGS += `pkg-config --libs gthread-2.0`
# frontend # frontend
OBJS += ../gp2x/main.o ../gp2x/menu.o ../gp2x/fonts.o ../gp2x/emu.o ../gp2x/usbjoy.o blit.o gp2x.o 940ctl_ym2612.o OBJS += ../gp2x/main.o ../gp2x/menu.o ../gp2x/fonts.o ../gp2x/emu.o ../gp2x/usbjoy.o blit.o \
gp2x.o 940ctl_ym2612.o ../gp2x/readpng.o
# Pico # Pico
OBJS += ../../Pico/Area.o ../../Pico/Cart.o ../../Pico/Utils.o ../../Pico/Memory.o ../../Pico/Misc.o \ OBJS += ../../Pico/Area.o ../../Pico/Cart.o ../../Pico/Utils.o ../../Pico/Memory.o ../../Pico/Misc.o \
../../Pico/Pico.o ../../Pico/Sek.o ../../Pico/VideoPort.o ../../Pico/Draw2.o ../../Pico/Draw.o \ ../../Pico/Pico.o ../../Pico/Sek.o ../../Pico/VideoPort.o ../../Pico/Draw2.o ../../Pico/Draw.o \
@ -66,7 +67,7 @@ tidy:
PicoDrive : $(OBJS) ../gp2x/helix/helix_mp3_x86.a PicoDrive : $(OBJS) ../gp2x/helix/helix_mp3_x86.a
@echo $@ @echo $@
@$(GCC) $(COPT) $^ $(LDFLAGS) -lm -Wl,-Map=PicoDrive.map -o $@ @$(GCC) $(COPT) $^ $(LDFLAGS) -lm -lpng -Wl,-Map=PicoDrive.map -o $@
../../cpu/mz80/mz80.o : ../../cpu/mz80/mz80.asm ../../cpu/mz80/mz80.o : ../../cpu/mz80/mz80.asm

View file

@ -257,13 +257,18 @@ void gp2x_video_setpalette(int *pal, int len)
memcpy(current_pal, pal, len*4); memcpy(current_pal, pal, len*4);
} }
void gp2x_video_flush_cache(void)
{
}
void gp2x_video_RGB_setscaling(int v_offs, int W, int H) void gp2x_video_RGB_setscaling(int v_offs, int W, int H)
{ {
} }
void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len) void gp2x_memcpy_buffers(int buffers, void *data, int offset, int len)
{ {
memcpy((char *)gp2x_screen + offset, data, len); if ((char *)gp2x_screen + offset != data)
memcpy((char *)gp2x_screen + offset, data, len);
} }
void gp2x_memcpy_all_buffers(void *data, int offset, int len) void gp2x_memcpy_all_buffers(void *data, int offset, int len)
@ -279,7 +284,7 @@ void gp2x_memset_all_buffers(int offset, int byte, int len)
void gp2x_pd_clone_buffer2(void) void gp2x_pd_clone_buffer2(void)
{ {
memset(gp2x_screen, 0, 320*240); memset(gp2x_screen, 0, 320*240*2);
} }
/* sound */ /* sound */

View file

@ -243,6 +243,8 @@ Changelog
+ Config profiles added (press left/right when saving config). + Config profiles added (press left/right when saving config).
* Changed key configuration behaviour to the one from gpfce (should be more * Changed key configuration behaviour to the one from gpfce (should be more
intuitive). intuitive).
+ Added some skinning capabilities to the menu system with default skin by
ketch. Delete skin directory if you want old behaviour.
1.32 1.32
+ Added some new scaling options. + Added some new scaling options.

BIN
skin/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
skin/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
skin/selector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

4
skin/skin.txt Normal file
View file

@ -0,0 +1,4 @@
// html-style hex color codes, ex. ff0000 is red, 0000ff is blue, etc.
text_color=ffffff
selection_color=c00000