From 7dae5fc15a960ad0fbe5a37b3bff727ca2582a17 Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Wed, 30 Dec 2009 15:31:50 +0000 Subject: [PATCH] .removed unecessary images (use rotation instead) .implemented interactive screen positioning & scaling in video option menu .usual code cleanup --- source/gx/gui/filesel.c | 5 +- source/gx/gui/gui.c | 377 +++++++++++++++--- source/gx/gui/gui.h | 11 +- source/gx/gui/menu.c | 364 +++++++++++------ source/gx/gx_video.c | 143 +++---- .../{Button_left.png => Button_arrow.png} | Bin ...on_left_over.png => Button_arrow_over.png} | Bin source/gx/images/Button_right.png | Bin 3257 -> 0 bytes source/gx/images/Button_right_over.png | Bin 3245 -> 0 bytes source/gx/images/Button_save.png | Bin 4452 -> 0 bytes source/gx/images/Button_save_over.png | Bin 4493 -> 0 bytes 11 files changed, 641 insertions(+), 259 deletions(-) rename source/gx/images/{Button_left.png => Button_arrow.png} (100%) rename source/gx/images/{Button_left_over.png => Button_arrow_over.png} (100%) delete mode 100644 source/gx/images/Button_right.png delete mode 100644 source/gx/images/Button_right_over.png delete mode 100644 source/gx/images/Button_save.png delete mode 100644 source/gx/images/Button_save_over.png diff --git a/source/gx/gui/filesel.c b/source/gx/gui/filesel.c index 86f8604..d8ca16c 100644 --- a/source/gx/gui/filesel.c +++ b/source/gx/gui/filesel.c @@ -103,13 +103,12 @@ static gui_menu menu_browser = { "Game Selection", -1,-1, - 0,0,10, + 0,0,10,0, NULL, NULL, bg_filesel, {&action_cancel, &action_select}, - {&arrow_up,&arrow_down}, - FALSE + {&arrow_up,&arrow_down} }; /*************************************************************************** diff --git a/source/gx/gui/gui.c b/source/gx/gui/gui.c index 9a561bc..0d42a8d 100644 --- a/source/gx/gui/gui.c +++ b/source/gx/gui/gui.c @@ -168,7 +168,7 @@ void GUI_DrawMenu(gui_menu *menu) if (menu->screenshot) { gxClearScreen((GXColor)BLACK); - gxDrawScreenshot(128); + gxDrawScreenshot(menu->screenshot); } else { @@ -287,33 +287,41 @@ void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out) if (image->state & IMAGE_SLIDE_LEFT) { temp = image->x + image->w; - if (max_offset < temp) max_offset = temp; + if (max_offset < temp) + max_offset = temp; } else if (image->state & IMAGE_SLIDE_RIGHT) { temp = 640 - image->x; - if (max_offset < temp) max_offset = temp; + if (max_offset < temp) + max_offset = temp; } if (image->state & IMAGE_SLIDE_TOP) { temp = image->y + image->h; - if (max_offset < temp) max_offset = temp; + if (max_offset < temp) + max_offset = temp; } else if (image->state & IMAGE_SLIDE_BOTTOM) { temp = 480 - image->y; - if (max_offset < temp) max_offset = temp; + if (max_offset < temp) + max_offset = temp; } } temp = max_offset; /* Alpha steps */ - int alpha = out ? 255 : 0; + int alpha = 0; int alpha_step = (255 * speed) / max_offset; - if (out) alpha_step = -alpha_step; + if (out) + { + alpha = 255; + alpha_step = -alpha_step; + } /* Let's loop until final position has been reached */ while (temp > 0) @@ -322,8 +330,10 @@ void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out) if (menu->screenshot) { gxClearScreen((GXColor)BLACK); - if (alpha > 127) gxDrawScreenshot(128); - else gxDrawScreenshot(255 - alpha); + if (alpha >= menu->screenshot) + gxDrawScreenshot(menu->screenshot); + else + gxDrawScreenshot(255 - alpha); } else { @@ -355,13 +365,17 @@ void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out) if ((image->state & IMAGE_FADE) && ((out && (image->alpha > alpha)) || (!out && (image->alpha < alpha)))) { /* FADE In-Out */ - if (image->state & IMAGE_REPEAT) gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha); - else if (image->state & IMAGE_VISIBLE)gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha); + if (image->state & IMAGE_REPEAT) + gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha); + else if (image->state & IMAGE_VISIBLE) + gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,alpha); } else { - if (image->state & IMAGE_REPEAT) gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha); - else if (image->state & IMAGE_VISIBLE)gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha); + if (image->state & IMAGE_REPEAT) + gxDrawTextureRepeat(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha); + else if (image->state & IMAGE_VISIBLE) + gxDrawTexture(image->texture,image->x+xoffset,image->y+yoffset,image->w,image->h,image->alpha); } } @@ -413,7 +427,9 @@ void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out) /* draw button + items */ item = &menu->items[menu->offset + i]; - if (button->data) gxDrawTexture(button->data->texture[0],button->x+xoffset,button->y+yoffset,button->w, button->h,item_alpha); + if (button->data) + gxDrawTexture(button->data->texture[0],button->x+xoffset,button->y+yoffset,button->w, button->h,item_alpha); + if (item->texture) { gxDrawTexture(item->texture,item->x+xoffset,item->y+yoffset,item->w,item->h,item_alpha); @@ -431,8 +447,10 @@ void GUI_DrawMenuFX(gui_menu *menu, u8 speed, u8 out) /* update alpha */ alpha += alpha_step; - if (alpha > 255) alpha = 255; - else if (alpha < 0) alpha = 0; + if (alpha > 255) + alpha = 255; + else if (alpha < 0) + alpha = 0; /* copy EFB to XFB */ gxSetScreen(); @@ -1187,12 +1205,9 @@ int GUI_OptionWindow(gui_menu *parent, char *title, char *items[], u8 nb_items) /* Option Box */ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *option, float step, float min, float max, u8 type) { - gx_texture *l_arrow[2]; - gx_texture *r_arrow[2]; - l_arrow[0] = gxTextureOpenPNG(Button_left_png,0); - l_arrow[1] = gxTextureOpenPNG(Button_left_over_png,0); - r_arrow[0] = gxTextureOpenPNG(Button_right_png,0); - r_arrow[1] = gxTextureOpenPNG(Button_right_over_png,0); + gx_texture *arrow[2]; + arrow[0] = gxTextureOpenPNG(Button_arrow_png,0); + arrow[1] = gxTextureOpenPNG(Button_arrow_over_png,0); gx_texture *window = gxTextureOpenPNG(Frame_s4_png,0); gx_texture *top = gxTextureOpenPNG(Frame_s4_title_png,0); @@ -1200,17 +1215,15 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio int xwindow = 166; int ywindow = 160; - /* text position */ - int ypos = 248; - /* arrows position */ int xleft = 206; int xright = 392; int yleft = 238; int yright = 238; - /* disable helper comment */ - if (parent->helpers[1]) parent->helpers[1]->data = 0; + /* disable action button helper */ + if (parent->helpers[1]) + parent->helpers[1]->data = 0; /* slide in */ char msg[16]; @@ -1224,13 +1237,9 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230); gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255); - /* draw title */ + /* display title */ FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE); - /* draw buttons */ - gxDrawTexture(l_arrow[0],xleft,yleft-yoffset,l_arrow[0]->width,l_arrow[0]->height,255); - gxDrawTexture(r_arrow[0],xright,yright-yoffset,r_arrow[0]->width,r_arrow[0]->height,255); - /* update display */ gxSetScreen(); @@ -1240,6 +1249,7 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio /* display option box */ int quit = 0; + int modified = 0; int selected = -1; s16 p; #ifdef HW_RVL @@ -1255,7 +1265,7 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio gxDrawTexture(window,xwindow,ywindow,window->width,window->height,230); gxDrawTexture(top,xwindow,ywindow,top->width,top->height,255); - /* draw title */ + /* display title */ FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20,(GXColor)WHITE); /* option type */ @@ -1273,7 +1283,7 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio } /* draw option text */ - FONT_writeCenter(msg,24,xwindow,xwindow+window->width,ypos+24,(GXColor)WHITE); + FONT_writeCenter(msg,24,xwindow,xwindow+window->width,272,(GXColor)WHITE); /* update inputs */ p = m_input.keys; @@ -1282,31 +1292,29 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio if (selected < 0) { /* nothing selected */ - gxDrawTexture(l_arrow[0],xleft,yleft,l_arrow[0]->width,l_arrow[0]->height,255); - gxDrawTexture(r_arrow[0],xright,yright,r_arrow[0]->width,r_arrow[0]->height,255); + gxDrawTexture(arrow[0],xleft,yleft,arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[0],xright,yright,arrow[0]->width,arrow[0]->height,180.0,255); } #ifdef HW_RVL else if (selected) { /* right button selected */ - gxDrawTexture(l_arrow[0],xleft,yleft,l_arrow[0]->width,l_arrow[0]->height,255); - gxDrawTexture(r_arrow[1],xright-4,yright-4,r_arrow[0]->width+8,r_arrow[0]->height+8,255); + gxDrawTexture(arrow[0],xleft,yleft,arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[1],xright-4,yright-4,arrow[1]->width+8,arrow[1]->height+8,180.0,255); } else { /* left button selected */ - gxDrawTexture(l_arrow[1],xleft-4,yleft-4,l_arrow[0]->width+8,l_arrow[0]->height+8,255); - gxDrawTexture(r_arrow[0],xright,yright,r_arrow[0]->width,r_arrow[0]->height,255); + gxDrawTexture(arrow[1],xleft-4,yleft-4,arrow[1]->width+8,arrow[1]->height+8,255); + gxDrawTextureRotate(arrow[0],xright,yright,arrow[0]->width,arrow[0]->height,180.0,255); } selected = -1; if (Shutdown) { - gxTextureClose(&l_arrow[0]); - gxTextureClose(&l_arrow[1]); - gxTextureClose(&r_arrow[0]); - gxTextureClose(&r_arrow[1]); + gxTextureClose(&arrow[0]); + gxTextureClose(&arrow[1]); gxTextureClose(&window); gxTextureClose(&top); gxTextureClose(&w_pointer); @@ -1325,10 +1333,18 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255); /* check for valid buttons */ - if ((x>=xleft)&&(x<=(xleft+l_arrow[0]->width))&&(y>=yleft)&&(y<=(yleft+l_arrow[0]->height))) + if ((x>=xleft)&&(x<=(xleft+arrow[0]->width))&&(y>=yleft)&&(y<=(yleft+arrow[0]->height))) + { selected = 0; - else if ((x>=xright)&&(x<=(xright+r_arrow[0]->width))&&(y>=yright)&&(y<=(yright+r_arrow[0]->height))) + if (p & PAD_BUTTON_A) + p |= PAD_BUTTON_LEFT; + } + else if ((x>=xright)&&(x<=(xright+arrow[0]->width))&&(y>=yright)&&(y<=(yright+arrow[0]->height))) + { selected = 1; + if (p & PAD_BUTTON_A) + p |= PAD_BUTTON_RIGHT; + } } #endif @@ -1336,7 +1352,7 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio gxSetScreen(); /* check input */ - if ((p&PAD_BUTTON_LEFT) || ((p & PAD_BUTTON_A) && (selected == 0))) + if (p&PAD_BUTTON_LEFT) { /* decrement option value */ if (type) @@ -1352,14 +1368,9 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio if (*(float *)option < min) *(float *)option = max; } - /* play sound effect */ - ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size, - ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL); - - /* option callback */ - if (cb) cb(); + modified = 1; } - else if ((p&PAD_BUTTON_RIGHT) || ((p & PAD_BUTTON_A) && (selected == 1))) + else if (p&PAD_BUTTON_RIGHT) { /* increment option value */ if (type) @@ -1375,6 +1386,17 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio if (*(float *)option > max) *(float *)option = min; } + modified = 1; + } + else if (p & PAD_BUTTON_B) + { + quit = 1; + } + + if (modified) + { + modified = 0; + /* play sound effect */ ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size, ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL); @@ -1382,8 +1404,6 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio /* option callback */ if (cb) cb(); } - - if (p & PAD_BUTTON_B) quit = 1; } /* slide out */ @@ -1397,7 +1417,7 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230); gxDrawTexture(top,xwindow,ywindow-yoffset,top->width,top->height,255); - /* draw title */ + /* display title */ FONT_writeCenter(title,20,xwindow,xwindow+window->width,ywindow+(top->height-20)/2+20-yoffset,(GXColor)WHITE); /* update display */ @@ -1407,22 +1427,253 @@ void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *optio yoffset += 60; } - /* restore helper comment */ - if (parent->helpers[1]) parent->helpers[1]->data = Key_A_png; + /* restore action button helper */ + if (parent->helpers[1]) + parent->helpers[1]->data = Key_A_png; /* final position */ GUI_DrawMenu(parent); gxSetScreen(); /* close textures */ - gxTextureClose(&l_arrow[0]); - gxTextureClose(&l_arrow[1]); - gxTextureClose(&r_arrow[0]); - gxTextureClose(&r_arrow[1]); + gxTextureClose(&arrow[0]); + gxTextureClose(&arrow[1]); gxTextureClose(&window); gxTextureClose(&top); } +/* Option Box with two parameters */ +void GUI_OptionBox2(gui_menu *parent, char *text_1, char *text_2, s16 *option_1, s16 *option_2, s16 step, s16 min, s16 max) +{ + gx_texture *arrow[2]; + arrow[0] = gxTextureOpenPNG(Button_arrow_png,0); + arrow[1] = gxTextureOpenPNG(Button_arrow_over_png,0); + gx_texture *window = gxTextureOpenPNG(Frame_s4_png,0); + + /* window position */ + int xwindow = 166; + int ywindow = 160; + + /* arrows position */ + int arrow_pos[4][2] = + { + {144,218}, + {452,218}, + {298,138}, + {298,298} + }; + + /* disable action button helper */ + if (parent->helpers[1]) + parent->helpers[1]->data = 0; + + /* slide in */ + char msg[16]; + int yoffset = ywindow + window->height; + while (yoffset > 0) + { + /* draw parent menu */ + GUI_DrawMenu(parent); + + /* draw window */ + gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230); + + /* update display */ + gxSetScreen(); + + /* slide speed */ + yoffset -= 60; + } + + /* display option box */ + int quit = 0; + int modified = 0; + s16 p; +#ifdef HW_RVL + int selected = -1; + int i,x,y; +#endif + + while (!quit) + { + /* draw parent menu */ + GUI_DrawMenu(parent); + + /* draw window */ + gxDrawTexture(window,xwindow,ywindow,window->width,window->height,230); + + /* draw options text */ + if (*option_1 < 0) sprintf(msg,"%s: -%02d",text_1,abs(*option_1)); + else sprintf(msg,"%s: +%02d",text_1,abs(*option_1)); + FONT_writeCenter(msg,24,xwindow,xwindow+window->width,240,(GXColor)WHITE); + if (*option_2 < 0) sprintf(msg,"%s: -%02d",text_2,abs(*option_2)); + else sprintf(msg,"%s: +%02d",text_2,abs(*option_2)); + FONT_writeCenter(msg,24,xwindow,xwindow+window->width,264,(GXColor)WHITE); + + /* update inputs */ + p = m_input.keys; + + /* draw buttons */ +#ifdef HW_RVL + switch (selected) + { + case 0: /* left button */ + gxDrawTexture(arrow[1],arrow_pos[0][0]-4,arrow_pos[0][1]-4,arrow[0]->width+8,arrow[0]->height+8,255); + gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255); + if (p & PAD_BUTTON_A) p |= PAD_BUTTON_LEFT; + break; + + case 1: /* right button */ + gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[1],arrow_pos[1][0]-4,arrow_pos[1][1]-4,arrow[0]->width+8,arrow[0]->height+8,180.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255); + if (p & PAD_BUTTON_A) p |= PAD_BUTTON_RIGHT; + break; + + case 2: /* up button */ + gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255); + gxDrawTextureRotate(arrow[1],arrow_pos[2][0]-4,arrow_pos[2][1]-4,arrow[0]->width+8,arrow[0]->height+8,90.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255); + if (p & PAD_BUTTON_A) p |= PAD_BUTTON_UP; + break; + + case 3: /* down button */ + gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255); + gxDrawTextureRotate(arrow[1],arrow_pos[3][0]-4,arrow_pos[3][1]-4,arrow[0]->width+8,arrow[0]->height+8,270.0,255); + if (p & PAD_BUTTON_A) p |= PAD_BUTTON_DOWN; + break; + + default: /* nothing selected */ + gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255); + break; + } + + if (Shutdown) + { + gxTextureClose(&arrow[0]); + gxTextureClose(&arrow[1]); + gxTextureClose(&window); + gxTextureClose(&w_pointer); + GUI_DeleteMenu(parent); + GUI_FadeOut(); + shutdown(); + SYS_ResetSystem(SYS_POWEROFF, 0, 0); + } + + /* update selection */ + selected = -1; + if (m_input.ir.valid) + { + /* get cursor position */ + x = m_input.ir.x; + y = m_input.ir.y; + + /* draw wiimote pointer */ + gxDrawTextureRotate(w_pointer, x-w_pointer->width/2, y-w_pointer->height/2, w_pointer->width, w_pointer->height,m_input.ir.angle,255); + + /* check for valid buttons */ + for (i=0; i<4; i++) + { + if ((x>=arrow_pos[i][0])&&(x<=(arrow_pos[i][0]+arrow[0]->width))&&(y>=arrow_pos[i][1])&&(y<=(arrow_pos[i][1]+arrow[0]->height))) + selected = i; + } + } +#else + gxDrawTexture(arrow[0],arrow_pos[0][0],arrow_pos[0][1],arrow[0]->width,arrow[0]->height,255); + gxDrawTextureRotate(arrow[0],arrow_pos[1][0],arrow_pos[1][1],arrow[0]->width,arrow[0]->height,180.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[2][0],arrow_pos[2][1],arrow[0]->width,arrow[0]->height,90.0,255); + gxDrawTextureRotate(arrow[0],arrow_pos[3][0],arrow_pos[3][1],arrow[0]->width,arrow[0]->height,270.0,255); +#endif + + /* update screen */ + gxSetScreen(); + + if (p&PAD_BUTTON_LEFT) + { + /* decrement option 1 value */ + *option_1 -= step; + if (*option_1 < min) + *option_1 = max; + modified = 1; + } + else if (p&PAD_BUTTON_RIGHT) + { + /* decrement option 1 value */ + *option_1 += step; + if (*option_1 > max) + *option_1 = min; + modified = 1; + } + else if (p&PAD_BUTTON_UP) + { + /* decrement option 2 value */ + *option_2 -= step; + if (*option_2 < min) + *option_2 = max; + modified = 1; + } + else if (p&PAD_BUTTON_DOWN) + { + /* increment option 2 value */ + *option_2 += step; + if (*option_2 > max) + *option_2 = min; + modified = 1; + } + else if (p & PAD_BUTTON_B) + { + quit = 1; + } + + if (modified) + { + modified = 0; + /* play sound effect */ + ASND_SetVoice(ASND_GetFirstUnusedVoice(),VOICE_MONO_16BIT,22050,0,(u8 *)button_over_pcm,button_over_pcm_size, + ((int)config.sfx_volume * 255) / 100,((int)config.sfx_volume * 255) / 100,NULL); + } + } + + /* slide out */ + yoffset = 0; ; + while (yoffset < (ywindow + window->height)) + { + /* draw parent menu */ + GUI_DrawMenu(parent); + + /* draw window */ + gxDrawTexture(window,xwindow,ywindow-yoffset,window->width,window->height,230); + + /* update display */ + gxSetScreen(); + + /* slide speed */ + yoffset += 60; + } + + /* restore action button helper */ + if (parent->helpers[1]) + parent->helpers[1]->data = Key_A_png; + + /* final position */ + GUI_DrawMenu(parent); + gxSetScreen(); + + /* close textures */ + gxTextureClose(&arrow[0]); + gxTextureClose(&arrow[1]); + gxTextureClose(&window); +} + /* Interactive Message Box */ /* Message Box displays a message until a specific action is completed */ diff --git a/source/gx/gui/gui.h b/source/gx/gui/gui.h index 2df2073..71a3a05 100644 --- a/source/gx/gui/gui.h +++ b/source/gx/gui/gui.h @@ -110,12 +110,12 @@ typedef struct u8 max_items; /* total number of items */ u8 max_buttons; /* total number of buttons */ u8 max_images; /* total number of background images */ + u8 screenshot; /* game screen background */ gui_item *items; /* menu items */ gui_butn *buttons; /* menu buttons */ gui_image *bg_images; /* background images */ gui_item *helpers[2]; /* left & right key comments */ gui_butn *arrows[2]; /* arrows buttons */ - bool screenshot; /* use gamescreen as background */ } gui_menu; typedef struct @@ -217,13 +217,11 @@ extern const u8 Button_icon_over_png[]; extern const u8 Button_icon_sm_png[]; extern const u8 Button_icon_sm_over_png[]; extern const u8 Button_up_png[]; -extern const u8 Button_down_png[]; extern const u8 Button_up_over_png[]; +extern const u8 Button_down_png[]; extern const u8 Button_down_over_png[]; -extern const u8 Button_right_png[]; -extern const u8 Button_left_png[]; -extern const u8 Button_right_over_png[]; -extern const u8 Button_left_over_png[]; +extern const u8 Button_arrow_png[]; +extern const u8 Button_arrow_over_png[]; /* Controller Settings */ extern const u8 Ctrl_4wayplay_png[]; @@ -286,6 +284,7 @@ extern int GUI_UpdateMenu(gui_menu *menu); extern int GUI_RunMenu(gui_menu *menu); extern int GUI_OptionWindow(gui_menu *parent, char *title, char *items[], u8 nb_items); extern void GUI_OptionBox(gui_menu *parent, optioncallback cb, char *title, void *option, float step, float min, float max, u8 type); +extern void GUI_OptionBox2(gui_menu *parent, char *text_1, char *text_2, s16 *option_1, s16 *option_2, s16 step, s16 min, s16 max); extern void GUI_MsgBoxOpen(char *title, char *msg, bool throbber); extern void GUI_MsgBoxUpdate(char *title, char *msg); extern void GUI_MsgBoxClose(void); diff --git a/source/gx/gui/menu.c b/source/gx/gui/menu.c index 8adaa8f..bb8652c 100644 --- a/source/gx/gui/menu.c +++ b/source/gx/gui/menu.c @@ -246,14 +246,14 @@ static gui_item items_system[7] = /* Video options menu */ static gui_item items_video[8] = { - {NULL,NULL,"Display: PROGRESSIVE", "Select video mode type", 52,132,276,48}, - {NULL,NULL,"TV mode: 50/60Hz", "Select video refresh rate", 52,132,276,48}, - {NULL,NULL,"Bilinear Filter: OFF", "Enable/disable hardware filtering", 52,132,276,48}, - {NULL,NULL,"NTSC Filter: COMPOSITE","Enable/disable NTSC software filtering", 52,132,276,48}, - {NULL,NULL,"Borders: OFF", "Enable/disable original overscan emulation",52,132,276,48}, - {NULL,NULL,"Aspect: ORIGINAL (4:3)","Select display aspect ratio", 52,132,276,48}, - {NULL,NULL,"DISPLAY POSITION", "Adjust display position", 52,132,276,48}, - {NULL,NULL,"DISPLAY SIZE", "Adjust display size", 52,132,276,48} + {NULL,NULL,"Display: PROGRESSIVE", "Select video mode type", 52,132,276,48}, + {NULL,NULL,"TV mode: 50/60Hz", "Select video refresh rate", 52,132,276,48}, + {NULL,NULL,"Bilinear Filter: OFF", "Enable/disable hardware filtering", 52,132,276,48}, + {NULL,NULL,"NTSC Filter: COMPOSITE", "Enable/disable NTSC software filtering", 52,132,276,48}, + {NULL,NULL,"Borders: OFF", "Enable/disable original overscan emulation",52,132,276,48}, + {NULL,NULL,"Aspect: ORIGINAL (4:3)", "Select display aspect ratio", 52,132,276,48}, + {NULL,NULL,"Screen Position (+0,+0)", "Adjust display position", 52,132,276,48}, + {NULL,NULL,"Screen Size (+0,+0)", "Adjust display size", 52,132,276,48} }; /* Preferences menu */ @@ -354,13 +354,12 @@ static gui_menu menu_main = { "", 0,0, - 9,9,4, + 9,9,4,0, items_main, buttons_main, bg_main, {NULL,NULL}, - {NULL,NULL}, - FALSE + {NULL,NULL} }; /* Main menu */ @@ -368,13 +367,12 @@ gui_menu menu_ctrls = { "Controller Settings", 0,0, - 13,13,8, + 13,13,8,0, items_ctrls, buttons_ctrls, bg_ctrls, {&action_cancel, &action_select}, - {NULL,NULL}, - FALSE + {NULL,NULL} }; /* Load Game menu */ @@ -383,16 +381,15 @@ static gui_menu menu_load = "Load Game", 0,0, #ifdef HW_RVL - 4,4,5, + 4,4,5,0, #else - 3,3,5, + 3,3,5,0, #endif items_load, buttons_load, bg_misc, {&action_cancel, &action_select}, - {NULL,NULL}, - FALSE + {NULL,NULL} }; /* Options menu */ @@ -400,13 +397,12 @@ static gui_menu menu_options = { "Settings", 0,0, - 5,5,5, + 5,5,5,0, items_options, buttons_options, bg_misc, {&action_cancel, &action_select}, - {NULL,NULL}, - FALSE + {NULL,NULL} }; /* System Options menu */ @@ -414,13 +410,12 @@ static gui_menu menu_system = { "System Settings", 0,0, - 6,4,6, + 6,4,6,0, items_system, buttons_list, bg_list, {&action_cancel, &action_select}, - {&arrow_up,&arrow_down}, - FALSE + {&arrow_up,&arrow_down} }; /* Video Options menu */ @@ -428,13 +423,12 @@ static gui_menu menu_video = { "Video Settings", 0,0, - 8,4,6, + 8,4,6,0, items_video, buttons_list, bg_list, {&action_cancel, &action_select}, - {&arrow_up,&arrow_down}, - FALSE + {&arrow_up,&arrow_down} }; /* Sound Options menu */ @@ -442,13 +436,12 @@ static gui_menu menu_audio = { "Audio Settings", 0,0, - 10,4,6, + 10,4,6,0, items_audio, buttons_list, bg_list, {&action_cancel, &action_select}, - {&arrow_up,&arrow_down}, - FALSE + {&arrow_up,&arrow_down} }; /* Sound Options menu */ @@ -456,13 +449,12 @@ static gui_menu menu_prefs = { "Menu Settings", 0,0, - 7,4,6, + 7,4,6,0, items_prefs, buttons_list, bg_list, {&action_cancel, &action_select}, - {&arrow_up,&arrow_down}, - FALSE + {&arrow_up,&arrow_down} }; @@ -750,7 +742,7 @@ static void soundmenu () { unsigned char *temp = memalign(32,YM2612GetContextSize()); if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(48000); + audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); if (temp) { YM2612Restore(temp); @@ -870,17 +862,28 @@ static void systemmenu () gui_menu *m = &menu_system; gui_item *items = m->items; - if (config.region_detect == 0) sprintf (items[0].text, "Console Region: AUTO"); - else if (config.region_detect == 1) sprintf (items[0].text, "Console Region: USA"); - else if (config.region_detect == 2) sprintf (items[0].text, "Console Region: EUR"); - else if (config.region_detect == 3) sprintf (items[0].text, "Console Region: JAP"); + if (config.region_detect == 0) + sprintf (items[0].text, "Console Region: AUTO"); + else if (config.region_detect == 1) + sprintf (items[0].text, "Console Region: USA"); + else if (config.region_detect == 2) + sprintf (items[0].text, "Console Region: EUR"); + else if (config.region_detect == 3) + sprintf (items[0].text, "Console Region: JAP"); + sprintf (items[1].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON"); sprintf (items[2].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF"); sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF"); - if (config.lock_on == TYPE_GG) sprintf (items[4].text, "Lock-On: GAME GENIE"); - else if (config.lock_on == TYPE_AR) sprintf (items[4].text, "Lock-On: ACTION REPLAY"); - else if (config.lock_on == TYPE_SK) sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES"); - else sprintf (items[4].text, "Lock-On: OFF"); + + if (config.lock_on == TYPE_GG) + sprintf (items[4].text, "Lock-On: GAME GENIE"); + else if (config.lock_on == TYPE_AR) + sprintf (items[4].text, "Lock-On: ACTION REPLAY"); + else if (config.lock_on == TYPE_SK) + sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES"); + else + sprintf (items[4].text, "Lock-On: OFF"); + sprintf (items[5].text, "Cartridge Swap: %s", config.hot_swap ? "ON":"OFF"); if (svp) @@ -905,21 +908,28 @@ static void systemmenu () { case 0: /*** Region Force ***/ config.region_detect = (config.region_detect + 1) % 4; - if (config.region_detect == 0) sprintf (items[0].text, "Console Region: AUTO"); - else if (config.region_detect == 1) sprintf (items[0].text, "Console Region: USA"); - else if (config.region_detect == 2) sprintf (items[0].text, "Console Region: EUR"); - else if (config.region_detect == 3) sprintf (items[0].text, "Console Region: JAP"); + + if (config.region_detect == 0) + sprintf (items[0].text, "Console Region: AUTO"); + else if (config.region_detect == 1) + sprintf (items[0].text, "Console Region: USA"); + else if (config.region_detect == 2) + sprintf (items[0].text, "Console Region: EUR"); + else if (config.region_detect == 3) + sprintf (items[0].text, "Console Region: JAP"); + if (cart.romsize) { /* force region & cpu mode */ set_region(); /* reinitialize timings */ - system_init (); + system_init(); memfile_autoload(config.sram_auto,-1); unsigned char *temp = memalign(32,YM2612GetContextSize()); - if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(48000); + if (temp) + memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); + audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); if (temp) { YM2612Restore(temp); @@ -961,11 +971,17 @@ static void systemmenu () case 4: /*** Cart Lock-On ***/ config.lock_on++; - if (config.lock_on > TYPE_SK) config.lock_on = 0; - if (config.lock_on == TYPE_GG) sprintf (items[4].text, "Lock-On: GAME GENIE"); - else if (config.lock_on == TYPE_AR) sprintf (items[4].text, "Lock-On: ACTION REPLAY"); - else if (config.lock_on == TYPE_SK) sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES"); - else sprintf (items[4].text, "Lock-On: OFF"); + if (config.lock_on > TYPE_SK) + config.lock_on = 0; + if (config.lock_on == TYPE_GG) + sprintf (items[4].text, "Lock-On: GAME GENIE"); + else if (config.lock_on == TYPE_AR) + sprintf (items[4].text, "Lock-On: ACTION REPLAY"); + else if (config.lock_on == TYPE_SK) + sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES"); + else + sprintf (items[4].text, "Lock-On: OFF"); + if (cart.romsize) { system_reset (); /* clear any patches first */ @@ -1000,25 +1016,53 @@ static void systemmenu () ****************************************************************************/ static void videomenu () { + u16 state[2]; int ret, quit = 0; gui_menu *m = &menu_video; gui_item *items = m->items; - if (config.render == 1) sprintf (items[0].text,"Display: INTERLACED"); - else if (config.render == 2) sprintf (items[0].text, "Display: PROGRESSIVE"); - else sprintf (items[0].text, "Display: ORIGINAL"); - if (config.tv_mode == 0) sprintf (items[1].text, "TV Mode: 60HZ"); - else if (config.tv_mode == 1) sprintf (items[1].text, "TV Mode: 50HZ"); - else sprintf (items[1].text, "TV Mode: 50/60HZ"); - sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF"); - if (config.ntsc == 1) sprintf (items[3].text, "NTSC Filter: COMPOSITE"); - else if (config.ntsc == 2) sprintf (items[3].text, "NTSC Filter: S-VIDEO"); - else if (config.ntsc == 3) sprintf (items[3].text, "NTSC Filter: RGB"); - else sprintf (items[3].text, "NTSC Filter: OFF"); - sprintf (items[4].text, "Borders: %s", config.overscan ? " ON" : "OFF"); - if (config.aspect == 1) sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); - else if (config.aspect == 2) sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); - else sprintf (items[5].text, "Aspect: FIT SCREEN"); + if (config.render == 1) + sprintf (items[0].text,"Display: INTERLACED"); + else if (config.render == 2) + sprintf (items[0].text, "Display: PROGRESSIVE"); + else + sprintf (items[0].text, "Display: ORIGINAL"); + + if (config.tv_mode == 0) + sprintf (items[1].text, "TV Mode: 60HZ"); + else if (config.tv_mode == 1) + sprintf (items[1].text, "TV Mode: 50HZ"); + else + sprintf (items[1].text, "TV Mode: 50/60HZ"); + + sprintf (items[2].text, "Bilinear Filter: %s", + config.bilinear ? " ON" : "OFF"); + + if (config.ntsc == 1) + sprintf (items[3].text, "NTSC Filter: COMPOSITE"); + else if (config.ntsc == 2) + sprintf (items[3].text, "NTSC Filter: S-VIDEO"); + else if (config.ntsc == 3) + sprintf (items[3].text, "NTSC Filter: RGB"); + else + sprintf (items[3].text, "NTSC Filter: OFF"); + + sprintf (items[4].text, "Borders: %s", + config.overscan ? "ON" : "OFF"); + + if (config.aspect == 1) + sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); + else if (config.aspect == 2) + sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); + else + sprintf (items[5].text, "Aspect: SCALED"); + + sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)", + (config.xshift < 0) ? "":"+", config.xshift, + (config.yshift < 0) ? "":"+", config.yshift); + sprintf (items[7].text, "Screen Scaling: (%s%02d,%s%02d)", + (config.xscale < 0) ? "":"+", config.xscale, + (config.yscale < 0) ? "":"+", config.yscale); GUI_InitMenu(m); @@ -1043,6 +1087,7 @@ static void videomenu () { /* progressive mode (60hz only) */ config.tv_mode = 0; + sprintf (items[1].text, "TV Mode: 60HZ"); } else { @@ -1050,46 +1095,57 @@ static void videomenu () config.render = 0; } } - if (config.render == 1) sprintf (items[0].text,"Display: INTERLACED"); - else if (config.render == 2) sprintf (items[0].text, "Display: PROGRESSIVE"); - else sprintf (items[0].text, "Display: ORIGINAL"); - if (config.tv_mode == 0) sprintf (items[1].text, "TV Mode: 60HZ"); - else if (config.tv_mode == 1) sprintf (items[1].text, "TV Mode: 50HZ"); - else sprintf (items[1].text, "TV Mode: 50/60HZ"); + if (config.render == 1) + sprintf (items[0].text,"Display: INTERLACED"); + else if (config.render == 2) + sprintf (items[0].text, "Display: PROGRESSIVE"); + else + sprintf (items[0].text, "Display: ORIGINAL"); break; case 1: /*** tv mode ***/ - if (config.render != 2) config.tv_mode = (config.tv_mode + 1) % 3; - if (config.tv_mode == 0) sprintf (items[1].text, "TV Mode: 60HZ"); - else if (config.tv_mode == 1) sprintf (items[1].text, "TV Mode: 50HZ"); - else sprintf (items[1].text, "TV Mode: 50/60HZ"); + if (config.render == 2) break; + config.tv_mode = (config.tv_mode + 1) % 3; + if (config.tv_mode == 0) + sprintf (items[1].text, "TV Mode: 60HZ"); + else if (config.tv_mode == 1) + sprintf (items[1].text, "TV Mode: 50HZ"); + else + sprintf (items[1].text, "TV Mode: 50/60HZ"); break; case 2: /*** bilinear filtering ***/ config.bilinear ^= 1; - sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF"); + sprintf (items[2].text, "Bilinear Filter: %s", + config.bilinear ? " ON" : "OFF"); break; case 3: /*** NTSC filter ***/ - config.ntsc ++; - if (config.ntsc > 3) config.ntsc = 0; - if (config.ntsc == 1) sprintf (items[3].text, "NTSC Filter: COMPOSITE"); - else if (config.ntsc == 2) sprintf (items[3].text, "NTSC Filter: S-VIDEO"); - else if (config.ntsc == 3) sprintf (items[3].text, "NTSC Filter: RGB"); - else sprintf (items[3].text, "NTSC Filter: OFF"); + config.ntsc = (config.ntsc + 1) % 4; + if (config.ntsc == 1) + sprintf (items[3].text, "NTSC Filter: COMPOSITE"); + else if (config.ntsc == 2) + sprintf (items[3].text, "NTSC Filter: S-VIDEO"); + else if (config.ntsc == 3) + sprintf (items[3].text, "NTSC Filter: RGB"); + else + sprintf (items[3].text, "NTSC Filter: OFF"); break; case 4: /*** overscan emulation ***/ config.overscan ^= 1; - sprintf (items[4].text, "Borders: %s", config.overscan ? " ON" : "OFF"); + sprintf (items[4].text, "Overscan Color: %s", + config.overscan ? "ORIGINAL" : "BLACK"); break; - case 5: /*** config.aspect ratio ***/ - config.aspect ++; - if (config.aspect > 2) config.aspect = 0; - if (config.aspect == 1) sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); - else if (config.aspect == 2) sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); - else sprintf (items[5].text, "Aspect: FIT SCREEN"); + case 5: /*** aspect ratio ***/ + config.aspect = (config.aspect + 1) % 3; + if (config.aspect == 1) + sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); + else if (config.aspect == 2) + sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); + else + sprintf (items[5].text, "Aspect: SCALED"); if (config.aspect) { @@ -1111,10 +1167,52 @@ static void videomenu () break; - case 6: + case 6: /*** screen position ***/ + if (cart.romsize) + { + state[0] = m->arrows[0]->state; + state[1] = m->arrows[1]->state; + m->max_buttons = 0; + m->max_images = 0; + m->arrows[0]->state = 0; + m->arrows[1]->state = 0; + m->screenshot = 255; + strcpy(m->title,""); + GUI_OptionBox2(m,"X Offset","Y Offset",&config.xshift,&config.yshift,1,-99,99); + m->max_buttons = 4; + m->max_images = 6; + m->arrows[0]->state = state[0]; + m->arrows[1]->state = state[1]; + m->screenshot = 0; + strcpy(m->title,"Video Settings"); + sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)", + (config.xshift < 0) ? "":"+", config.xshift, + (config.yshift < 0) ? "":"+", config.yshift); + } break; - case 7: + case 7: /*** screen scaling ***/ + if (cart.romsize) + { + state[0] = m->arrows[0]->state; + state[1] = m->arrows[1]->state; + m->max_buttons = 0; + m->max_images = 0; + m->arrows[0]->state = 0; + m->arrows[1]->state = 0; + m->screenshot = 255; + strcpy(m->title,""); + GUI_OptionBox2(m,"X Scale","Y Scale",&config.xscale,&config.yscale,1,-99,99); + m->max_buttons = 4; + m->max_images = 6; + m->arrows[0]->state = state[0]; + m->arrows[1]->state = state[1]; + m->screenshot = 0; + strcpy(m->title,"Video Settings"); + sprintf (items[7].text, "Screen Scaling: (%s%02d,%s%02d)", + (config.xscale < 0) ? "":"+", config.xscale, + (config.yscale < 0) ? "":"+", config.yscale); + } break; case -1: @@ -1161,20 +1259,35 @@ static void ctrlmenu_raz(void) } /* update buttons navigation */ - if (input.dev[0] != NO_DEVICE) m->buttons[0].shift[3] = 2; - else if (input.dev[4] != NO_DEVICE) m->buttons[0].shift[3] = 6; - else m->buttons[0].shift[3] = 0; - if (input.dev[4] != NO_DEVICE) m->buttons[1].shift[3] = 5; - else if (input.dev[0] != NO_DEVICE) m->buttons[1].shift[3] = 1; - else m->buttons[1].shift[3] = 0; - if (input.dev[1] != NO_DEVICE) m->buttons[2].shift[1] = 1; - else if (input.dev[4] != NO_DEVICE) m->buttons[2].shift[1] = 4; - else m->buttons[2].shift[1] = 0; - if (input.dev[3] != NO_DEVICE) m->buttons[6].shift[0] = 1; - else if (input.dev[0] != NO_DEVICE) m->buttons[6].shift[0] = 4; - else m->buttons[6].shift[0] = 0; - if (input.dev[4] != NO_DEVICE) m->buttons[5].shift[1] = 1; - else m->buttons[5].shift[1] = 0; + if (input.dev[0] != NO_DEVICE) + m->buttons[0].shift[3] = 2; + else if (input.dev[4] != NO_DEVICE) + m->buttons[0].shift[3] = 6; + else + m->buttons[0].shift[3] = 0; + if (input.dev[4] != NO_DEVICE) + m->buttons[1].shift[3] = 5; + else if (input.dev[0] != NO_DEVICE) + m->buttons[1].shift[3] = 1; + else + m->buttons[1].shift[3] = 0; + if (input.dev[1] != NO_DEVICE) + m->buttons[2].shift[1] = 1; + else if (input.dev[4] != NO_DEVICE) + m->buttons[2].shift[1] = 4; + else + m->buttons[2].shift[1] = 0; + if (input.dev[3] != NO_DEVICE) + m->buttons[6].shift[0] = 1; + else if (input.dev[0] != NO_DEVICE) + m->buttons[6].shift[0] = 4; + else + m->buttons[6].shift[0] = 0; + if (input.dev[4] != NO_DEVICE) + m->buttons[5].shift[1] = 1; + else + m->buttons[5].shift[1] = 0; + if (input.dev[5] != NO_DEVICE) { m->buttons[6].shift[1] = 1; @@ -1184,12 +1297,17 @@ static void ctrlmenu_raz(void) if (input.dev[7] != NO_DEVICE) m->buttons[8].shift[1] = 1; else m->buttons[8].shift[1] = 0; } - else m->buttons[7].shift[1] = 0; + else + { + m->buttons[7].shift[1] = 0; + } + } + else + { + m->buttons[6].shift[1] = 0; } - else m->buttons[6].shift[1] = 0; } - static void ctrlmenu(void) { int player = 0; @@ -1328,10 +1446,14 @@ static void ctrlmenu(void) { case 0: /* update port 1 system */ if (cart.hw.jcart) break; - if (input.system[0] == SYSTEM_MOUSE) input.system[0] +=3; /* lightguns are never used on Port 1 */ - else input.system[0] ++; - if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) input.system[0] +=3; - if (input.system[0] == SYSTEM_WAYPLAY) input.system[1] = SYSTEM_WAYPLAY; + if (input.system[0] == SYSTEM_MOUSE) + input.system[0] +=3; /* lightguns are never used on Port 1 */ + else + input.system[0]++; + if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) + input.system[0] +=3; + if (input.system[0] == SYSTEM_WAYPLAY) + input.system[1] = SYSTEM_WAYPLAY; if (input.system[0] > SYSTEM_WAYPLAY) { input.system[0] = NO_SYSTEM; @@ -1380,8 +1502,10 @@ static void ctrlmenu(void) case 1: /* update port 2 system */ if (cart.hw.jcart) break; input.system[1] ++; - if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) input.system[1] ++; - if (input.system[1] == SYSTEM_WAYPLAY) input.system[0] = SYSTEM_WAYPLAY; + if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) + input.system[1] ++; + if (input.system[1] == SYSTEM_WAYPLAY) + input.system[0] = SYSTEM_WAYPLAY; if (input.system[1] > SYSTEM_WAYPLAY) { input.system[1] = NO_SYSTEM; @@ -2187,7 +2311,7 @@ void MainMenu (void) /* check if a game is running */ if (cart.romsize) { - m->screenshot = 1; + m->screenshot = 128; m->bg_images[0].state &= ~IMAGE_VISIBLE; m->buttons[3].state |= BUTTON_SELECT_SFX; m->buttons[5].state |= BUTTON_SELECT_SFX; @@ -2279,7 +2403,7 @@ void MainMenu (void) gxClearScreen((GXColor)BLACK); gxSetScreen(); system_init(); - audio_init(48000); + audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); system_reset(); memfile_autoload(config.sram_auto,-1); quit = 1; diff --git a/source/gx/gx_video.c b/source/gx/gx_video.c index 3d6995e..b75ca26 100644 --- a/source/gx/gx_video.c +++ b/source/gx/gx_video.c @@ -24,7 +24,6 @@ #include "shared.h" #include "font.h" -#include "sms_ntsc.h" #include "aram.h" #include "md_ntsc.h" #include "sms_ntsc.h" @@ -446,109 +445,117 @@ static void gxResetView(GXRModeObj *tvmode) GX_Flush(); } -/* Reset GX/VI scaler */ -static void gxResetScale(u32 width, u32 height) +/* Manage Aspect Ratio */ +static void gxSetAspectRatio(int *xscale, int *yscale) { - int temp = 0; - int xscale, yscale, xshift, yshift; - - /* Aspect Ratio (depends on current configuration) */ + /* original aspect ratio */ + /* the following values have been deducted from comparison with a real 50/60hz Mega Drive */ if (config.aspect) { - /* original aspect ratio */ - /* the following values have been deducted from comparison with a real 50/60hz Mega Drive */ if (config.overscan) { /* borders are emulated */ - xscale = 358 + ((reg[12] & 1)*2) - gc_pal; - yscale = vdp_pal + ((gc_pal && !config.render) ? 143 : 120); + *xscale = 358 + ((reg[12] & 1)*2) - gc_pal; + *yscale = vdp_pal + ((gc_pal && !config.render) ? 143 : 120); } else { /* borders are simulated (black) */ - xscale = 325 + ((reg[12] & 1)*2) - gc_pal; - yscale = bitmap.viewport.h / 2; - if (vdp_pal && (!gc_pal || config.render)) yscale = yscale * 240 / 288; - else if (!vdp_pal && gc_pal && !config.render) yscale = yscale * 288 / 240; + *xscale = 325 + ((reg[12] & 1)*2) - gc_pal; + *yscale = bitmap.viewport.h / 2; + if (vdp_pal && (!gc_pal || config.render)) *yscale = *yscale * 240 / 288; + else if (!vdp_pal && gc_pal && !config.render) *yscale = *yscale * 288 / 240; } /* 16/9 correction */ - if (config.aspect & 2) xscale = (xscale * 3) / 4; - - xshift = config.xshift; - yshift = 2 - vdp_pal + 2*(gc_pal & !config.render) + config.yshift; + if (config.aspect & 2) + *xscale = (*xscale * 3) / 4; } + + /* manual aspect ratio (default is fullscreen) */ else { - /* manual aspect ratio (default is fullscreen) */ if (config.overscan) { /* borders are emulated */ - xscale = 352; - yscale = (gc_pal && !config.render) ? (vdp_pal ? (268*144 / bitmap.viewport.h):143) : (vdp_pal ? (224*144 / bitmap.viewport.h):120); + *xscale = 352; + *yscale = (gc_pal && !config.render) ? (vdp_pal ? (268*144 / bitmap.viewport.h):143) : (vdp_pal ? (224*144 / bitmap.viewport.h):120); } else { /* borders are simulated (black) */ - xscale = 320; - yscale = (gc_pal && !config.render) ? 134 : 112; + *xscale = 320; + *yscale = (gc_pal && !config.render) ? 134 : 112; } - /* user scaling */ - xscale += config.xscale; - yscale += config.yscale; - - xshift = config.xshift; - yshift = config.yshift; + /* add user scaling */ + *xscale += config.xscale; + *yscale += config.yscale; } +} - /* double resolution modes */ - if (config.render) - { - yscale *= 2; - yshift *= 2; - } +/* Reset GX/VI hardware scaler */ +static void gxResetScaler(u32 width, u32 height) +{ + /* get Aspect Ratio (depends on current configuration) */ + int xscale,yscale; + gxSetAspectRatio(&xscale, &yscale); - /* GX scaler (by default, use EFB maximal width) */ + /* GX horizontal scaling (done during EFB rendering) */ + /* by default, use maximal EFB width */ rmode->fbWidth = 640; if (!config.bilinear && !config.ntsc) { /* filtering (soft or hard) is disabled, let VI handles horizontal scaling */ - /* if possible, let GX simply doubles the width, otherwise disable GX stretching completely */ - if ((width * 2) <= 640) rmode->fbWidth = width * 2; - else if (width <= 640) rmode->fbWidth = width; + if ((width * 2) <= 640) + rmode->fbWidth = width * 2; /* GX scaling enabled (simple doubler) */ + else if (width <= 640) + rmode->fbWidth = width; /* GX scaling disabled */ } - /* horizontal scaling (GX/VI) */ - if (xscale > (rmode->fbWidth/2)) + /* VI horizontal scaling (done during EFB->XFB copy) */ + int offset = 0; + if ((xscale * 2) > rmode->fbWidth) { /* max width = 720 pixels */ if (xscale > 360) { /* save offset for later */ - temp = xscale - 360; + offset = xscale - 360; + + /* maximal width */ xscale = 360; } - /* enable VI scaler */ + /* VI horizontal scaling is enabled */ rmode->viWidth = xscale * 2; rmode->viXOrigin = (720 - (xscale * 2)) / 2; - /* set GX scaling to max EFB width */ - xscale = temp + (rmode->fbWidth/2); + /* update GX horizontal scaling (disabled if no offset) */ + xscale = (rmode->fbWidth / 2) + ((offset * rmode->fbWidth) / rmode->viWidth); } else { - /* disable VI scaler */ + /* VI horizontal scaling is disabled */ rmode->viWidth = rmode->fbWidth; rmode->viXOrigin = (720 - rmode->fbWidth) / 2; } - /* update GX scaler (Vertex Position Matrix) */ - square[6] = square[3] = xscale + xshift; - square[0] = square[9] = -xscale + xshift; - square[4] = square[1] = yscale + yshift; - square[7] = square[10] = -yscale + yshift; + /* Adjust screen position */ + int xshift = (config.xshift * rmode->fbWidth) / rmode->viWidth; + int yshift = (config.yshift * rmode->efbHeight) / rmode->viHeight; + + /* Configure GX vertical scaling (480i/576i/480p) */ + if (config.render) + { + yscale = yscale * 2; + } + + /* Set GX scaler (Vertex Position matrix) */ + square[6] = square[3] = xshift + xscale; + square[0] = square[9] = xshift - xscale; + square[4] = square[1] = yshift + yscale; + square[7] = square[10] = yshift - yscale; DCFlushRange(square, 32); GX_InvVtxCache(); } @@ -759,26 +766,28 @@ void gxDrawScreenshot(u8 alpha) { if (!rmode) return; - /* retrieve gamescreen texture */ + /* get current game screen texture */ GXTexObj texobj; GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_LoadTexObj(&texobj, GX_TEXMAP0); GX_InvalidateTexAll(); - /* retrieve current xscale/xshift values */ - s32 xscale = (rmode->viWidth + square[6] - square[0] - rmode->fbWidth) / 2 - (vmode->viWidth - 640)/2; - s32 xshift = (square[6] + square[0]) / 2; + /* get current aspect ratio */ + int xscale,yscale; + gxSetAspectRatio(&xscale, &yscale); - /* apply current position/size */ + /* adjust horizontal scaling */ + xscale = (xscale * vmode->fbWidth) / vmode->viWidth; + + /* adjust screen position */ + int xshift = (config.xshift * vmode->fbWidth) / vmode->viWidth; + int yshift = (config.yshift * vmode->efbHeight) / vmode->viHeight; + + /* set vertices position & size */ s32 x = xshift - xscale; - s32 y = square[7]; + s32 y = yshift - (yscale * 2); s32 w = xscale * 2; - s32 h = square[4] - square[7]; - if (rmode->efbHeight < 480) - { - y = y * 2; - h = h * 2; - } + s32 h = yscale * 4; /* draw textured quad */ GX_Begin(GX_QUADS, GX_VTXFMT0, 4); @@ -808,7 +817,7 @@ void gxCopyScreenshot(gx_texture *texture) GX_InvalidateTexAll(); /* scale texture to EFB width */ - s32 w = bitmap.viewport.x ? (704) : (640); + s32 w = bitmap.viewport.x ? 704 : 640; s32 h = (bitmap.viewport.h + 2*bitmap.viewport.y) * 2; s32 x = -w/2; s32 y = -(240+ 2*bitmap.viewport.y); @@ -1256,10 +1265,10 @@ void gx_video_Stop(void) VIDEO_SetPostRetraceCallback(gx_input_UpdateMenu); /* reset VI & adjust overscan */ - gxDrawScreenshot(0xff); vmode->viWidth = config.screen_w; vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth)/2; VIDEO_Configure(vmode); + gxDrawScreenshot(0xff); gxSetScreen(); } @@ -1379,7 +1388,7 @@ void gx_video_Update(void) else rmode = tvmodes[gc_pal*3 + interlaced]; /* reset aspect ratio */ - gxResetScale(vwidth,vheight); + gxResetScaler(vwidth,vheight); /* reset GX */ gxResetView(rmode); diff --git a/source/gx/images/Button_left.png b/source/gx/images/Button_arrow.png similarity index 100% rename from source/gx/images/Button_left.png rename to source/gx/images/Button_arrow.png diff --git a/source/gx/images/Button_left_over.png b/source/gx/images/Button_arrow_over.png similarity index 100% rename from source/gx/images/Button_left_over.png rename to source/gx/images/Button_arrow_over.png diff --git a/source/gx/images/Button_right.png b/source/gx/images/Button_right.png deleted file mode 100644 index 2751be501ac5dd884935eeb584c2aa0e86658488..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3257 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 diff --git a/source/gx/images/Button_right_over.png b/source/gx/images/Button_right_over.png deleted file mode 100644 index e51557a99e9f7d79ec8dcd0e1f141c37fefd4152..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3245 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 diff --git a/source/gx/images/Button_save.png b/source/gx/images/Button_save.png deleted file mode 100644 index 32c7441566c3420bf42304862924c57cda85a6cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4452 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