// Modified by oggzee & usptactical #include #include #include #include #include #include #include #include "gui.h" #include "sys.h" #include "fat.h" #include "video.h" #include "cache.h" #include "cfg.h" #include "grid.h" #include "coverflow.h" #include "menu.h" #include "console.h" #include "png.h" #include "gettext.h" #include "sort.h" #include "wgui.h" #include "guimenu.h" #include "intro4_jpg.h" extern void *bg_buf_rgba; extern void *bg_buf_ycbr; extern bool imageNotFound; extern int page_gi; int gui_mode = 0; int gui_style = GUI_STYLE_GRID; bool loadGame; bool suppressCoverDrawing; /* Constants */ int COVER_WIDTH = 160; int COVER_HEIGHT = 225; #define SAFE_PNGU_RELEASE(CTX) if(CTX){PNGU_ReleaseImageContext(CTX);CTX=NULL;} static int grr_init = 0; static int grx_init = 0; static int prev_cover_style = CFG_COVER_STYLE_2D; static int prev_cover_height; static int prev_cover_width; int game_select = -1; s32 __Gui_DrawPngA(void *img, u32 x, u32 y); s32 __Gui_DrawPngRA(void *img, u32 x, u32 y, int width, int height); void CopyRGBA(char *src, int srcWidth, int srcHeight, char *dest, int dstWidth, int dstHeight, int srcX, int srcY, int dstX, int dstY, int w, int h); void CompositeRGBA(char *bg_buf, int bg_w, int bg_h, int x, int y, char *img, int width, int height); void ResizeRGBA(char *img, int imgWidth, int imgHeight, char *resize, int width, int height); void RGB_to_RGBA(const unsigned char *src, unsigned char *dst, const int width, const int height, unsigned char alpha); void* Load_JPG_RGB(const unsigned char my_jpg[], int *w, int *h); // FLOW_Z camera float cam_f = 0.0f; float cam_dir = 1.0; float cam_z = -578.0F; guVector cam_look = {319.5F, 239.5F, 0.0F}; //AA GRRLIB_texImg aa_texBuffer[4]; //Mtx GXmodelView2D; extern unsigned char bgImg[]; //extern unsigned char bgImg_wide[]; extern unsigned char bg_gui[]; extern unsigned char introImg2[]; extern unsigned char introImg3[]; extern unsigned char introImg41[]; extern unsigned char coverImg[]; extern unsigned char coverImg_full[]; //extern unsigned char coverImg_wide[]; extern unsigned char pointer[]; extern unsigned char hourglass[]; extern unsigned char star_icon[]; extern unsigned char gui_font[]; GRRLIB_texImg tx_bg; GRRLIB_texImg tx_bg_con; GRRLIB_texImg tx_nocover; GRRLIB_texImg tx_nocover_full; extern GRRLIB_texImg tx_hourglass_full; // coverflow GRRLIB_texImg tx_pointer; GRRLIB_texImg tx_hourglass; GRRLIB_texImg tx_star; GRRLIB_texImg tx_font; GRRLIB_texImg tx_font_clock; s32 __Gui_GetPngDimensions(void *img, u32 *w, u32 *h) { IMGCTX ctx = NULL; PNGUPROP imgProp; s32 ret; /* Select PNG data */ ctx = PNGU_SelectImageFromBuffer(img); if (!ctx) { ret = -1; goto out; } /* Get image properties */ ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) { ret = -1; goto out; } /* Set image width and height */ *w = imgProp.imgWidth; *h = imgProp.imgHeight; /* Success */ ret = 0; out: /* Free memory */ if (ctx) PNGU_ReleaseImageContext(ctx); return ret; } s32 __Gui_DrawPng(void *img, u32 x, u32 y) { IMGCTX ctx = NULL; PNGUPROP imgProp; s32 ret; /* Select PNG data */ ctx = PNGU_SelectImageFromBuffer(img); if (!ctx) { ret = -1; goto out; } /* Get image properties */ ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) { ret = -1; goto out; } /* Draw image */ Video_DrawPng(ctx, imgProp, x, y); /* Success */ ret = 0; out: /* Free memory */ if (ctx) PNGU_ReleaseImageContext(ctx); return ret; } void Gui_InitConsole(void) { /* Initialize console */ Con_Init(CONSOLE_XCOORD, CONSOLE_YCOORD, CONSOLE_WIDTH, CONSOLE_HEIGHT); } void Gui_Console_Enable(void) { if (!__console_disable) return; Video_DrawBg(); // current frame buffer __console_enable(_Video_GetFB(-1)); } IMGCTX Gui_OpenPNG(void *img, int *w, int *h) { IMGCTX ctx = NULL; PNGUPROP imgProp; int ret; // Select PNG data ctx = PNGU_SelectImageFromBuffer(img); if (!ctx) { return NULL; } // Get image properties ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK || imgProp.imgWidth == 0 || imgProp.imgWidth > 1024 || imgProp.imgHeight == 0 || imgProp.imgHeight > 1024) { PNGU_ReleaseImageContext(ctx); return NULL; } if (w) *w = imgProp.imgWidth; if (h) *h = imgProp.imgHeight; return ctx; } void* Gui_DecodePNG(IMGCTX ctx) { PNGUPROP imgProp; void *img_buf = NULL; int ret; if (ctx == NULL) return NULL; // Get image properties ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) { return NULL; } // alloc img_buf = memalign(32, imgProp.imgWidth * imgProp.imgHeight * 4); if (img_buf == NULL) { return NULL; } // decode ret = PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, imgProp.imgWidth, imgProp.imgHeight, 255, imgProp.imgWidth, imgProp.imgHeight, img_buf); return img_buf; } int Gui_DecodePNG_scale_to(IMGCTX ctx, void *img_buf, int dest_w, int dest_h) { PNGUPROP imgProp; int width, height; int ret; if (ctx == NULL) return -1; // Get image properties ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) return -1; width = imgProp.imgWidth; height = imgProp.imgHeight; if (width != dest_w || height != dest_h) { // fix size char *resize_buf = NULL; // decode resize_buf = Gui_DecodePNG(ctx); if (!resize_buf) return -1; // resize ResizeRGBA(resize_buf, width, height, img_buf, dest_w, dest_h); // free SAFE_FREE(resize_buf); } else { // Decode image PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, width, height, 255, dest_w, dest_h, img_buf); } return 0; } int Gui_DecodePNG_scaleBG_to(IMGCTX ctx, void *img_buf) { PNGUPROP imgProp; int width, height; int ret; if (ctx == NULL) return -1; // Get image properties ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) return -1; width = imgProp.imgWidth; height = imgProp.imgHeight; if (height != BACKGROUND_HEIGHT || width < BACKGROUND_WIDTH) { return -1; } if (width > BACKGROUND_WIDTH) { // fix size char *resize_buf = NULL; // decode resize_buf = Gui_DecodePNG(ctx); if (!resize_buf) { return -1; } if (CFG.widescreen) { // resize ResizeRGBA(resize_buf, width, height, img_buf, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); } else { // crop int x = (width - BACKGROUND_WIDTH) / 2; if (x<0) x = 0; CopyRGBA(resize_buf, width, height, img_buf, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, x, 0, 0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); } // free SAFE_FREE(resize_buf); } else { // Decode image PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, width, height, 255, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, img_buf); } return 0; } void* Gui_AllocBG() { return memalign(32, BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 4); } void *Gui_DecodePNG_scaleBG(IMGCTX ctx) { void *img_buf = NULL; int ret; if (ctx == NULL) return NULL; img_buf = Gui_AllocBG(); if (img_buf == NULL) return NULL; ret = Gui_DecodePNG_scaleBG_to(ctx, img_buf); if (ret) { SAFE_FREE(img_buf); return NULL; } return img_buf; } int Gui_LoadBG_data_to(void *data, void *dest_buf) { IMGCTX ctx = NULL; int ret; ctx = Gui_OpenPNG(data, NULL, NULL); if (ctx == NULL) { return -1; } ret = Gui_DecodePNG_scaleBG_to(ctx, dest_buf); PNGU_ReleaseImageContext(ctx); return ret; } void* Gui_LoadBG_data(void *data) { void *img_buf; int ret; img_buf = Gui_AllocBG(); if (img_buf == NULL) return NULL; ret = Gui_LoadBG_data_to(data, img_buf); if (ret) { SAFE_FREE(img_buf); } return img_buf; } int Gui_LoadBG_to(char *path, void *dest_buf) { void *data = NULL; int ret = -1; ret = Fat_ReadFile(path, &data); if (ret <= 0 || data == NULL) { return -1; } ret = Gui_LoadBG_data_to(data, dest_buf); SAFE_FREE(data); return ret; } void* Gui_LoadBG(char *path) { void *data = NULL; void *img_buf = NULL; int ret = -1; ret = Fat_ReadFile(path, &data); if (ret <= 0 || data == NULL) { return NULL; } img_buf = Gui_LoadBG_data(data); SAFE_FREE(data); return img_buf; } int Gui_OverlayBg(char *path, void *bg_buf) { void *img_buf = NULL; img_buf = Gui_LoadBG(path); if (img_buf == NULL) { return -1; } // overlay CompositeRGBA(bg_buf, BACKGROUND_WIDTH, BACKGROUND_HEIGHT, 0, 0, img_buf, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); SAFE_FREE(img_buf); return 0; } void Gui_LoadBackground(void) { s32 ret = -1; Video_AllocBg(); // Try to open background image from SD if (*CFG.background) { ret = Gui_LoadBG_to(CFG.background, bg_buf_rgba); } // if failed, use builtin if (ret) { ret = Gui_LoadBG_data_to(bgImg, bg_buf_rgba); } // Overlay char path[200]; ret = -1; if (CFG.widescreen) { snprintf(D_S(path), "%s/bg_overlay_w.png", CFG.theme_path); ret = Gui_OverlayBg(path, bg_buf_rgba); } if (ret) { snprintf(D_S(path), "%s/bg_overlay.png", CFG.theme_path); ret = Gui_OverlayBg(path, bg_buf_rgba); } // save background to ycbr Video_SaveBgRGBA(); } void Gui_DrawBackground(void) { if (CFG.direct_launch) return; // Load background Gui_LoadBackground(); // Draw background Video_DrawBg(); } void Gui_DrawIntro(void) { GXRModeObj *rmode = _Video_GetVMode(); int con_x = 32; int con_y = 16; int con_w = 640-32*2; int con_h = 480-16*2; int w = con_w/8; // 72 int h = con_h/16; // 28 int i, x, y; char *title = "Configurable USB Loader"; void *img_buf = NULL; int i41 = 0; time_t t = time(NULL); struct tm *ti = localtime(&t); // tm_mon starts at 0 // tm_mday starts at 1 if ((ti->tm_mon == 3 && ti->tm_mday == 1) || CFG.intro == 41) { CFG.intro = 2; i41 = 1; } else { if (CFG.direct_launch && CFG.intro==0) { CON_InitEx(rmode, con_x, con_y, con_w, con_h); __console_disable = 1; return; } } if (CFG.intro == 1) { CON_InitEx(rmode, con_x, con_y, con_w, con_h); Con_SetPosition((w-strlen(title))/2, h/2); printf("%s", title); Con_SetPosition(0,0); goto print_ver; } // Draw the intro image //VIDEO_WaitVSync(); //__Gui_DrawPng(introImg, 0, 0); get_time(&TIME.intro1); IMGCTX ctx = NULL; img_buf = memalign(32, rmode->fbWidth * rmode->xfbHeight * 4); if (!img_buf) return; if (CFG.intro == 4) { int imgw, imgh; void *rgb = NULL; void *rgba = NULL; rgb = Load_JPG_RGB(intro4_jpg, &imgw, &imgh); if (!rgb) goto out; if (imgw == rmode->fbWidth && imgh == rmode->xfbHeight) { RGB_to_RGBA(rgb, img_buf, imgw, imgh, 255); } else { rgba = memalign(32, imgw * imgh * 4); RGB_to_RGBA(rgb, rgba, imgw, imgh, 255); ResizeRGBA(rgba, imgw, imgh, img_buf, rmode->fbWidth, rmode->xfbHeight); SAFE_FREE(rgba); } SAFE_FREE(rgb); } else { if (CFG.intro == 2) { ctx = Gui_OpenPNG(introImg2, NULL, NULL); } else { ctx = Gui_OpenPNG(introImg3, NULL, NULL); } if (!ctx) goto out; Gui_DecodePNG_scale_to(ctx, img_buf, rmode->fbWidth, rmode->xfbHeight); PNGU_ReleaseImageContext(ctx); ctx = NULL; } // if (i41) { ctx = Gui_OpenPNG(introImg41, NULL, NULL); if (ctx) { PNGUPROP imgProp; int x, y; PNGU_GetImageProperties(ctx, &imgProp); x = rmode->fbWidth / 2 - imgProp.imgWidth / 2; y = rmode->xfbHeight / 2 - imgProp.imgHeight / 2; PNGU_DECODE_TO_COORDS_RGBA8(ctx, x, y, imgProp.imgWidth, imgProp.imgHeight, 255, rmode->fbWidth, rmode->xfbHeight, img_buf); PNGU_ReleaseImageContext(ctx); ctx = NULL; } } // //VIDEO_WaitVSync(); Video_DrawRGBA(0, 0, img_buf, rmode->fbWidth, rmode->xfbHeight); out: get_time(&TIME.intro2); Video_AllocBg(); memcpy(bg_buf_rgba, img_buf, BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 4); memcpy(bg_buf_ycbr, _Video_GetFB(-1), BACKGROUND_WIDTH * BACKGROUND_HEIGHT * 2); //CON_InitTr(rmode, 552, 424, 88, 48, CONSOLE_BG_COLOR); CON_InitTr(rmode, con_x, con_y, con_w, con_h, CONSOLE_BG_COLOR); Con_Clear(); print_ver: x = w - 12; // 60 y = h - 3; // 25 for (i=0;i 0) { imageNotFound = false; if (path) strcopy(path, filepath, 200); } if (ret <= 0 && load_noimage) { coverpath = cfg_get_covers_path(cover_style); L_retry2: snprintf(filepath, sizeof(filepath), "%s/noimage.png", coverpath); ret = Fat_ReadFile(filepath, p_imgData); if (ret <= 0) { if (cover_style == CFG_COVER_STYLE_2D && coverpath == CFG.covers_path) { coverpath = CFG.covers_path_2d; goto L_retry2; } } } return ret; } void DrawCoverImg(u8 *discid, char *img_buf, int width, int height) { char *bg_buf = NULL; char *star_buf = NULL; void *fav_buf = NULL; IMGCTX ctx = NULL; s32 ret; // get background bg_buf = memalign(32, width * height * 4); if (!bg_buf) return; Video_GetBG(COVER_XCOORD, COVER_YCOORD, bg_buf, width, height); // composite img to bg CompositeRGBA(bg_buf, width, height, 0, 0, img_buf, width, height); // favorite? if (is_favorite(discid)) { // star PNGUPROP imgProp; // Select PNG data ret = Load_Theme_Image("favorite.png", &fav_buf); if (ret == 0 && fav_buf) { ctx = PNGU_SelectImageFromBuffer(fav_buf); } else { ctx = PNGU_SelectImageFromBuffer(star_icon); } if (!ctx) goto out; // Get image properties ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) goto out; if (imgProp.imgWidth > width || imgProp.imgHeight > height) goto out; // alloc star img buf star_buf = memalign(32, imgProp.imgWidth * imgProp.imgHeight * 4); if (!star_buf) goto out; // decode ret = PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, imgProp.imgWidth, imgProp.imgHeight, 255, imgProp.imgWidth, imgProp.imgHeight, star_buf); // composite star CompositeRGBA(bg_buf, width, height, COVER_WIDTH - imgProp.imgWidth, 0, // right upper corner star_buf, imgProp.imgWidth, imgProp.imgHeight); } out: SAFE_PNGU_RELEASE(ctx); SAFE_FREE(fav_buf); SAFE_FREE(star_buf); // draw Video_DrawRGBA(COVER_XCOORD, COVER_YCOORD, bg_buf, width, height); SAFE_FREE(bg_buf); } void Gui_DrawCover(u8 *discid) { void *builtin = coverImg; void *imgData; s32 ret, size; imageNotFound = true; if (CFG.covers == 0) return; imgData = builtin; ret = Gui_LoadCover_style(discid, &imgData, true, CFG.cover_style, NULL); if (ret <= 0) imgData = builtin; size = ret; u32 width=0, height=0; /* Get image dimensions */ ret = __Gui_GetPngDimensions(imgData, &width, &height); /* If invalid image, use default noimage */ if (ret) { imageNotFound = true; if (imgData != builtin) free(imgData); imgData = builtin; ret = __Gui_GetPngDimensions(imgData, &width, &height); if (ret) return; } char *img_buf = NULL; char *resize_buf = NULL; IMGCTX ctx = NULL; img_buf = memalign(32, COVER_WIDTH * COVER_HEIGHT * 4); if (!img_buf) { ret = -1; goto out; } // Select PNG data ctx = PNGU_SelectImageFromBufferX(imgData, size); if (!ctx) { ret = -1; goto out; } // resize needed? if ((width != COVER_WIDTH) || (height != COVER_HEIGHT)) { // alloc tmp resize buf resize_buf = memalign(32, width * height * 4); if (!resize_buf) { ret = -1; goto out; } // decode ret = PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, width, height, 255, width, height, resize_buf); // resize ResizeRGBA(resize_buf, width, height, img_buf, COVER_WIDTH, COVER_HEIGHT); // discard tmp resize buf SAFE_FREE(resize_buf); } else { // decode ret = PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, width, height, 255, width, height, img_buf); } SAFE_PNGU_RELEASE(ctx); DrawCoverImg(discid, img_buf, COVER_WIDTH, COVER_HEIGHT); out: SAFE_FREE(img_buf); SAFE_FREE(resize_buf); SAFE_PNGU_RELEASE(ctx); /* Free memory */ if (imgData != builtin) free(imgData); } // return: // 0: theme image found // 1: global image found // -1: not founf int Load_Theme_Image2(char *name, void **img_buf, bool global) { char path[200]; void *data = NULL; int ret; u32 width, height; *img_buf = NULL; // try theme-specific file snprintf(D_S(path), "%s/%s", CFG.theme_path, name); ret = Fat_ReadFile(path, &data); if (ret > 0 && data) { ret = __Gui_GetPngDimensions(data, &width, &height); if (ret == 0) { *img_buf = data; dbg_printf("img: %s\n", path); return 0; } SAFE_FREE(data); } if (!global) return -1; // failed, try global snprintf(D_S(path), "%s/%s", USBLOADER_PATH, name); ret = Fat_ReadFile(path, &data); if (ret > 0 && data) { ret = __Gui_GetPngDimensions(data, &width, &height); if (ret == 0) { *img_buf = data; dbg_printf("img: %s\n", path); return 1; } SAFE_FREE(data); } // failed return -1; } int Load_Theme_Image(char *name, void **img_buf) { int ret = Load_Theme_Image2(name, img_buf, true); if (ret > 0) ret = 0; return ret; } s32 __Gui_DrawPngA(void *img, u32 x, u32 y) { IMGCTX ctx = NULL; PNGUPROP imgProp; s32 ret; /* Select PNG data */ ctx = PNGU_SelectImageFromBuffer(img); if (!ctx) { ret = -1; goto out; } /* Get image properties */ ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) { ret = -1; goto out; } char *img_buf; img_buf = memalign(32, imgProp.imgWidth * imgProp.imgHeight * 4); if (!img_buf) { ret = -1; goto out; } // decode ret = PNGU_DECODE_TO_COORDS_RGBA8(ctx, 0, 0, imgProp.imgWidth, imgProp.imgHeight, 255, imgProp.imgWidth, imgProp.imgHeight, img_buf); // combine Video_CompositeRGBA(x, y, img_buf, imgProp.imgWidth, imgProp.imgHeight); // draw Video_DrawRGBA(x, y, img_buf, imgProp.imgWidth, imgProp.imgHeight); SAFE_FREE(img_buf); /* Success */ ret = 0; out: /* Free memory */ if (ctx) PNGU_ReleaseImageContext(ctx); return ret; } void CopyRGBA(char *src, int srcWidth, int srcHeight, char *dest, int dstWidth, int dstHeight, int srcX, int srcY, int dstX, int dstY, int w, int h) { int x, y; for (y=0; y> 8; nx = ix+1; if (nx >= imgWidth) nx = imgWidth - 1; ry = (y << 8) * imgHeight / height; fny = ry & 0xff; fiy = 0x100 - fny; iy = ry >> 8; ny = iy+1; if (ny >= imgHeight) ny = imgHeight - 1; // source pixel pointers (syx i=index n=next) u8 *rp = (u8*)&((int*)resize)[y*width + x]; u8 *sii = (u8*)&((int*)img)[iy*imgWidth + ix]; u8 *sin = (u8*)&((int*)img)[iy*imgWidth + nx]; u8 *sni = (u8*)&((int*)img)[ny*imgWidth + ix]; u8 *snn = (u8*)&((int*)img)[ny*imgWidth + nx]; // pixel factors (fyx) u32 fii = fiy * fix; u32 fin = fiy * fnx; u32 fni = fny * fix; u32 fnn = fny * fnx; // pre-multiply factors with alpha fii *= (u32)sii[3]; fin *= (u32)sin[3]; fni *= (u32)sni[3]; fnn *= (u32)snn[3]; // compute alpha u32 fff; fff = fii + fin + fni + fnn; rp[3] = fff >> 16; // compute color for (i=0; i<3; i++) { // for each R,G,B if (fff == 0) { rp[i] = 0; } else { rp[i] = ( (u32)sii[i] * fii + (u32)sin[i] * fin + (u32)sni[i] * fni + (u32)snn[i] * fnn ) / fff; } } } } } // destination: bg_buf void CompositeRGBA(char *bg_buf, int bg_w, int bg_h, int x, int y, char *img, int width, int height) { int ix, iy; char *c, *bg, a; c = img; for (iy=0; iy> 2 << 2; height4 = (height + 3) >> 2 << 2; if (width != width4 || height != height4) { buf2 = mem_alloc(width4 * height4 * 4); if (buf2 == NULL) goto out; PadRGBA(buf1, width, height, buf2, width4, height4); SAFE_FREE(buf1); buf1 = buf2; buf2 = NULL; } if (dest == NULL) { dest = memalign (32, width4 * height4 * 4); if (dest == NULL) goto out; } memcheck(); RGBA_to_4x4((u8*)buf1, (u8*)dest, width4, height4); //dbg_printf("RGB8 %dx%d %dx%d %dx%d\n", // imgProp.imgWidth, imgProp.imgHeight, width, height, width4, height4); my_texture.data = dest; my_texture.w = width; my_texture.h = height; my_texture.tex_format = GX_TF_RGBA8; GRRLIB_FlushTex(&my_texture); out: SAFE_FREE(buf1); SAFE_FREE(buf2); if (ctx) PNGU_ReleaseImageContext(ctx); return my_texture; } /** * Method used to convert a RGBA8 image into CMPR */ GRRLIB_texImg Convert_to_CMPR(void *img, int width, int height, void *dest) { GRRLIB_texImg my_texture; int ret; void *buf1 = NULL; memset(&my_texture, 0, sizeof(GRRLIB_texImg)); int size = GX_GetTexBufferSize(width, height, GX_TF_RGBA8, GX_FALSE, 0); buf1 = memalign (32, size); if (buf1 == NULL) goto out; RGBA_to_4x4((u8*)img, (u8*)buf1, width, height); if (dest == NULL) { size = GX_GetTexBufferSize(width, height, GX_TF_CMPR, GX_FALSE, 0); dest = memalign (32, size); if (dest == NULL) goto out; } ret = PNGU_4x4RGBA8_To_CMPR(buf1, width, height, dest); if (ret != PNGU_OK) goto out; my_texture.data = dest; my_texture.w = width; my_texture.h = height; my_texture.tex_format = GX_TF_CMPR; GRRLIB_FlushTex(&my_texture); out: SAFE_FREE(buf1); return my_texture; } /** * Decodes a PNG to CMPR * * @param my_png[] PNG image * @param width png image width * @param height png image height * @param *dest image destination (CMPR-encoded) */ GRRLIB_texImg Gui_LoadTexture_CMPR(const unsigned char my_png[], int width, int height, void *dest, char *path) { PNGUPROP imgProp; IMGCTX ctx = NULL; GRRLIB_texImg my_texture; int ret; void *buf1 = NULL; void *buf2 = NULL; memset(&my_texture, 0, sizeof(GRRLIB_texImg)); ctx = PNGU_SelectImageFromBuffer(my_png); if (ctx == NULL) goto out; ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) goto out; if (width == 0 && height == 0 && dest == NULL) { width = imgProp.imgWidth; height = imgProp.imgHeight; } // CMPR allocation has to be a multiple of 8 //u32 imgheight, imgwidth; //imgheight = imgProp.imgHeight & ~7u; //imgwidth = imgProp.imgWidth & ~7u; // instead of trimming we will pad. // check if we need to resize if ((imgProp.imgHeight != height) || (imgProp.imgWidth != width)) { //dbg_printf("cmpr resize %dx%d %dx%d %s\n", // imgProp.imgWidth, imgProp.imgHeight, width, height, path); // get RGBA8 version of image buf1 = memalign (32, imgProp.imgWidth * imgProp.imgHeight * 4); if (buf1 == NULL) goto out; ret = PNGU_DecodeToRGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, buf1, 0, 255); if (ret != PNGU_OK) { if (ret == -666) Gui_HandleBadCoverImage(path); goto out; } // allocate for resize to passed in dimensions buf2 = mem_alloc(width * height * 4); if (buf2 == NULL) goto out; ResizeRGBA(buf1, imgProp.imgWidth, imgProp.imgHeight, buf2, width, height); SAFE_FREE(buf1); // convert to cmpr PNGU_RGBA8_To_CMPR(buf2, width, height, dest); } else { if (dest == NULL) { int size = GX_GetTexBufferSize(imgProp.imgWidth, imgProp.imgHeight, GX_TF_CMPR, GX_FALSE, 0); dest = mem_alloc(size); if (dest == NULL) goto out; } ret = PNGU_DecodeToCMPR_Pad(ctx, imgProp.imgWidth, imgProp.imgHeight, dest); if (ret != PNGU_OK) { if (ret == -666) Gui_HandleBadCoverImage(path); goto out; } } my_texture.w = width; my_texture.h = height; my_texture.data = dest; my_texture.tex_format = GX_TF_CMPR; GRRLIB_FlushTex(&my_texture); out: SAFE_FREE(buf1); SAFE_FREE(buf2); if (ctx) PNGU_ReleaseImageContext(ctx); return my_texture; } u32 upperPower(u32 width) { u32 i = 8; u32 maxWidth = 1024; while (i < width && i < maxWidth) i <<= 1; return i; } // For powers of two void resizeD2x2(u8 *dst, const u8 *src, u32 srcWidth, u32 srcHeight) { u32 i = 0, i0 = 0, i1 = 4; u32 i2 = srcWidth * 4; u32 i3 = (srcWidth + 1) * 4; u32 dstWidth = srcWidth >> 1; u32 dstHeight = srcHeight >> 1; u32 w4 = srcWidth * 4; u32 x, y; for (y = 0; y < dstHeight; ++y) { for (x = 0; x < dstWidth; ++x) { dst[i] = ((u32)src[i0] + src[i1] + src[i2] + src[i3]) >> 2; dst[i + 1] = ((u32)src[i0 + 1] + src[i1 + 1] + src[i2 + 1] + src[i3 + 1]) >> 2; dst[i + 2] = ((u32)src[i0 + 2] + src[i1 + 2] + src[i2 + 2] + src[i3 + 2]) >> 2; dst[i + 3] = ((u32)src[i0 + 3] + src[i1 + 3] + src[i2 + 3] + src[i3 + 3]) >> 2; i += 4; i0 += 8; i1 += 8; i2 += 8; i3 += 8; } i0 += w4; i1 += w4; i2 += w4; i3 += w4; } } void ColorizeImage(void *img, int w, int h, u32 color) { u32 *p = (u32*)img; int n = w * h; int i; for (i=0; i>= 1; nHeight >>= 1; } nWidth = width; nHeight = height; rgb_src = buf2; u8 *pdest = dest; // cmpr for (i=0; i>= 1; nHeight >>= 1; } // done my_texture.w = width; my_texture.h = height; my_texture.data = dest; my_texture.tex_format = GX_TF_CMPR; my_texture.tex_lod = maxlod; GRRLIB_FlushTex(&my_texture); out: SAFE_FREE(buf1); SAFE_FREE(buf2); if (!my_texture.data) SAFE_FREE(destbuf); if (ctx) PNGU_ReleaseImageContext(ctx); return my_texture; } /** * Method used by the cache to paste 2d cover images into the nocover_full image */ GRRLIB_texImg Gui_LoadTexture_fullcover(const unsigned char my_png[], int width, int height, int frontCoverWidth, void *dest, char *path) { PNGUPROP imgProp; IMGCTX ctx = NULL; GRRLIB_texImg my_texture; int ret; int frontCoverStart = tx_nocover_full.w - frontCoverWidth; void *buf1 = NULL; void *buf2 = NULL; void *buf3 = NULL; memset(&my_texture, 0, sizeof(GRRLIB_texImg)); ctx = PNGU_SelectImageFromBuffer(my_png); if (ctx == NULL) goto out; ret = PNGU_GetImageProperties(ctx, &imgProp); if (ret != PNGU_OK) goto out; //allocate for RGBA8 2D cover buf1 = memalign (32, imgProp.imgWidth * imgProp.imgHeight * 4); if (buf1 == NULL) goto out; ret = PNGU_DecodeToRGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, buf1, 0, 255); if (ret != PNGU_OK) { if (ret == -666) Gui_HandleBadCoverImage(path); goto out; } //check if we need to resize if (imgProp.imgWidth != frontCoverWidth || imgProp.imgHeight != height) { buf2 = memalign (32, frontCoverWidth * height * 4); if (buf2 == NULL) goto out; ResizeRGBA(buf1, imgProp.imgWidth, imgProp.imgHeight, buf2, frontCoverWidth, height); SAFE_FREE(buf1); buf1 = buf2; buf2 = NULL; } //allocate for RGBA8 nocover_full image buf2 = memalign (32, GRRLIB_TextureSize(&tx_nocover_full)); if (buf2 == NULL) goto out; C4x4_to_RGBA(tx_nocover_full.data, buf2, tx_nocover_full.w, tx_nocover_full.h); //check if we need to resize if (tx_nocover_full.w != width || tx_nocover_full.h != height) { buf3 = memalign (32, height * width * 4); if (buf3 == NULL) goto out; ResizeRGBA(buf2, tx_nocover_full.w, tx_nocover_full.h, buf3, width, height); SAFE_FREE(buf2); buf2 = buf3; buf3 = NULL; } //the full cover image is layed out like this: back | spine | front //so we want to paste the passed in image in the front section CompositeRGBA(buf2, width, height, frontCoverStart, 0, //place where front cover is located buf1, frontCoverWidth, height); if (CFG.gui_compress_covers) { my_texture = Convert_to_CMPR(buf2, width, height, dest); my_texture.tex_format = GX_TF_CMPR; } else { RGBA_to_4x4((u8*)buf2, (u8*)dest, width, height); my_texture.data = dest; my_texture.w = width; my_texture.h = height; my_texture.tex_format = GX_TF_RGBA8; GRRLIB_FlushTex(&my_texture); } out: SAFE_FREE(buf1); SAFE_FREE(buf2); if (ctx) PNGU_ReleaseImageContext(ctx); return my_texture; } /** * Method used to paste the src image into the dest image (fullcover size) */ GRRLIB_texImg Gui_paste_into_fullcover(void *src, int src_w, int src_h, void *dest, int dest_w, int dest_h) { int height, width; int width_front; void *buf1 = NULL; void *buf2 = NULL; GRRLIB_texImg my_texture; memset(&my_texture, 0, sizeof(GRRLIB_texImg)); if (!dest) goto out; buf1 = memalign (32, src_w * src_h * 4); if (buf1 == NULL) goto out; C4x4_to_RGBA(src, buf1, src_w, src_h); buf2 = memalign (32, dest_w * dest_h * 4); if (buf2 == NULL) goto out; C4x4_to_RGBA(dest, buf2, dest_w, dest_h); //the full cover image is layed out like this: back | spine | front //so we want to paste the passed in image in the front section //COVER_WIDTH_FRONT = (int)(COVER_HEIGHT / 1.4) >> 2 << 2; // 512x336 ; 240 = 336/1.4 ; 240+32+240=512 width_front = (int)(dest_h / 1.4) >> 2 << 2; CompositeRGBA(buf2, dest_w, dest_h, //place where front cover is located dest_w - (width_front/2) - (src_w/2), (dest_h/2) - (src_h/2), buf1, src_w, src_h); SAFE_FREE(buf1); if (CFG.gui_compress_covers) { //CMPR is divisible by 8 height = dest_h & ~7u; width = dest_w & ~7u; my_texture = Convert_to_CMPR(buf2, width, height, buf1); } else { buf1 = memalign(32, dest_w * dest_h * 4); RGBA_to_4x4((u8*)buf2, (u8*)buf1, dest_w, dest_h); my_texture.data = buf1; my_texture.w = dest_w; my_texture.h = dest_h; GRRLIB_FlushTex(&my_texture); } out:; SAFE_FREE(buf2); return my_texture; } /** * Reads a JPG file from disk and decompresses it into a 4x4 RGBA * @param path The absolute path to the jpg file * @return GRRLIB_texImg */ GRRLIB_texImg Gui_LoadJPGFromPath(char *path) { s32 ret; void *imgData = NULL; GRRLIB_texImg tx; //init the tex memset(&tx, 0, sizeof(GRRLIB_texImg)); //read in the file ret = Fat_ReadFile(path, &imgData); if (ret <= 0 || imgData==NULL) goto out; //load the image tx = my_GRRLIB_LoadTextureJPG(imgData); if (tx.w == -666) Gui_HandleBadCoverImage(path); out: SAFE_FREE(imgData); return tx; } /** * Draws a 4x4 RGBA image onto the screen. * To be used in console mode only. * @param tx The image to draw * @param xpos The X position * @param ypos The Y position * @param dest_w The desired image width to draw * @param dest_h The desired image height to draw * @return void */ void Gui_DrawImage_Console(GRRLIB_texImg *tx, int xpos, int ypos, int dest_w, int dest_h) { void *buf1 = NULL; void *buf2 = NULL; int width4, height4; //anything to draw? if (tx->data == NULL) return; //make sure final dimensions are divisible by 4 width4 = (dest_w + 3) >> 2 << 2; height4 = (dest_h + 3) >> 2 << 2; //allocate temp storage for resize buf1 = mem_alloc (tx->w * tx->h * 4); if (buf1 == NULL) goto out; buf2 = memalign (32, width4 * height4 * 4); if (buf2 == NULL) goto out; //convert to RGBA, resize and draw C4x4_to_RGBA(tx->data, buf1, tx->w, tx->h); ResizeRGBA(buf1, tx->w, tx->h, buf2, width4, height4); Video_DrawRGBA(xpos, ypos, buf2, width4, height4); out: SAFE_FREE(buf1); SAFE_FREE(buf2); } /** * Draws the theme preview image * @param id The id(name) of the theme to draw **/ void Gui_DrawThemePreviewX(char *name, int id, int X, int Y, int W, int H) { char theme_path[200]; GRRLIB_texImg tx; //did we get a name to draw? if ((name == NULL) || (strlen(name) < 1)) return; //create the image path - images are in ./theme_previews dir snprintf(D_S(theme_path), "%s/theme_previews/%d.jpg", USBLOADER_PATH, id); //try to read in the image tx = Gui_LoadJPGFromPath(theme_path); if (tx.data == NULL) { //draw nocover image tx = Gui_LoadTexture_RGBA8(coverImg, COVER_WIDTH, COVER_HEIGHT, NULL, NULL); } //draw the image if (CFG.debug == 3) printf("X:%d Y:%d W:%d H:%d\n", X, Y, W, H); Gui_DrawImage_Console(&tx, X, Y, W, H); SAFE_FREE(tx.data); } void Gui_DrawThemePreview(char *name, int id) { Gui_DrawThemePreviewX(name, id, CFG.theme_previewX, CFG.theme_previewY, CFG.theme_previewW, CFG.theme_previewH); } void Gui_DrawThemePreviewLarge(char *name, int id) { int con_h = 16 * 3; // 2 lines of pixels will be overwritten by console // intentional, because the jpg->rgba->c4x4->rgba conversion will // corrupt the bottom 2 lines because h (250) is not a multiple of 4 // hence con_h+2 int h = 480 - con_h + 2; int w = (640 * h / 480) / 2 * 2; int x = (640 - w) / 2 / 2 * 2; int y = 0; Video_Clear(COLOR_BLACK); Gui_DrawThemePreviewX(name, id, x, y, w, h); CON_InitEx(_Video_GetVMode(), 0, 480-con_h, 640, con_h); printf("%15s %s: %s\n", " ", gt("Theme"), name); printf("%15s %s", " ", gt("Press any button...")); __console_flush(0); Wpad_WaitButtonsCommon(); Gui_InitConsole(); Video_DrawBg(); } #if 0 void cache2_tex_alloc(struct M2_texImg *dest, int w, int h) { int src_size = w * h * 4; // data exists and big enough? if ((dest->tx.data == NULL) || (dest->size < src_size)) { dest->tx.data = LARGE_realloc(dest->tx.data, src_size); //dest->tx.data = LARGE_alloc(src_size); dest->size = src_size; } dest->tx.w = w; dest->tx.h = h; } void cache2_tex(struct M2_texImg *dest, GRRLIB_texImg *src) { //int src_size = src->w * src->h * 4; int fmt = src->tex_format ? src->tex_format : GX_TF_RGBA8; int src_size = GX_GetTexBufferSize(src->w, src->h, fmt, GX_FALSE, 0); if (src->data == NULL) return; // realloc cache2_tex_alloc(dest, src->w, src->h); void *data = dest->tx.data; if (!data) return; memcpy(data, src->data, src_size); memcpy(&dest->tx, src, sizeof (GRRLIB_texImg)); dest->tx.data = data; // reset as above will overwrite it GRRLIB_FlushTex(&dest->tx); // free src texture SAFE_FREE(src->data); src->w = src->h = 0; } void cache2_tex_alloc_fullscreen(struct M2_texImg *dest) { GXRModeObj *rmode = _Video_GetVMode(); cache2_tex_alloc(dest, rmode->fbWidth, rmode->efbHeight); } void cache2_GRRLIB_tex_alloc(GRRLIB_texImg *dest, int w, int h) { int src_size = w * h * 4; void *m2_buf; if (dest->data) return; // alloc new m2_buf = LARGE_memalign(32, src_size); if (m2_buf == NULL) return; dest->data = m2_buf; dest->w = w; dest->h = h; } void cache2_GRRLIB_tex_alloc_fullscreen(GRRLIB_texImg *dest) { GXRModeObj *rmode = _Video_GetVMode(); cache2_GRRLIB_tex_alloc(dest, rmode->fbWidth, rmode->efbHeight); } #endif void Gui_AllocTextureFullscreen(GRRLIB_texImg *dest) { GXRModeObj *rmode = _Video_GetVMode(); GRRLIB_AllocTextureData(dest, rmode->fbWidth, rmode->efbHeight); } long long render_cpu; // usec long long render_gpu; // usec long long render_busy; // usec long long render_idle; // usec void Gui_Render() { static long long t0 = 0; static long long t1 = 0; static long long t2 = 0; t0 = gettime(); if (CFG.debug) { GRRLIB_Rectangle(15,15,620,30, 0x404040B0, 1); // frame = busy (cpu+gpu) + idle GRRLIB_Printf(20, 20, &tx_font, 0xB0B0FFFF, 1, "f:%5.2f = b:%5.2f (c:%5.2f+g:%5.2f) + i:%5.2f ms", (float)(render_busy + render_idle)/1000.0, (float)render_busy/1000.0, (float)render_cpu/1000.0, (float)render_gpu/1000.0, (float)render_idle/1000.0); } _GRRLIB_Render(); GX_DrawDone(); //__console_disable=0; __console_flush(-1); // debug t1 = gettime(); _GRRLIB_VSync(); if (t2) { render_cpu = diff_usec(t2, t0); render_gpu = diff_usec(t0, t1); render_busy = diff_usec(t2, t1); } t2 = gettime(); render_idle = diff_usec(t1, t2); if (gui_style == GUI_STYLE_FLOW_Z) { GX_SetZMode (GX_FALSE, GX_NEVER, GX_TRUE); } } // outside of main gui loop // renders also wgui and pointer void Gui_Render_Out(ir_t *ir) { wgui_input_save2(ir, NULL); wgui_desk_render(NULL, NULL); Gui_draw_pointer(ir); Gui_Render(); } void Gui_DrawImgFullScreen(GRRLIB_texImg *tex, const u32 color, bool antialias) { int save_aa = GRRLIB_Settings.antialias; GRRLIB_Settings.antialias = antialias; // even though tex could be 640x528 in 50 Hz mode // we use 640x480 coordinates because guortho is fixed at 640x480 GRRLIB_DrawImgRect(0, 0, 640, 480, tex, color); GRRLIB_Settings.antialias = save_aa; } /** * Renders the current scene to a texture and stores it in the global aa_texBuffer array. * @param aaStep int position in the array to store the created tex * @return void */ void Gui_RenderAAPass(int aaStep) { if (aa_method == 0) { if (aa_texBuffer[aaStep].data == NULL) { // first time, allocate Gui_AllocTextureFullscreen(&aa_texBuffer[aaStep]); if (aa_texBuffer[aaStep].data == NULL) return; } GRRLIB_AAScreen2Texture_buf(&aa_texBuffer[aaStep], GX_TRUE); } else { // new slightly faster method // also takes less memory - only 1 buffer required if (aa_texBuffer[0].data == NULL) { // first time, allocate Gui_AllocTextureFullscreen(&aa_texBuffer[0]); if (aa_texBuffer[0].data == NULL) return; } if (aaStep > 0) { u32 color, alpha; alpha = 0xFF - 0xFF / (aaStep + 1); color = 0xFFFFFF00 | alpha; Gui_DrawImgFullScreen(&aa_texBuffer[0], color, false); } if (aaStep < CFG.gui_antialias - 1) { GRRLIB_AAScreen2Texture_buf(&aa_texBuffer[0], GX_TRUE); } } } void Gui_Init() { if (CFG.gui == 0) return; if (grr_init) return; VIDEO_WaitVSync(); if (GRRLIB_Init_VMode(_Video_GetVMode(), _Video_GetFB(0), _Video_GetFB(1))) { printf(gt("Error GRRLIB init")); printf("\n"); sleep(1); return; } VIDEO_WaitVSync(); grr_init = 1; } bool Load_Theme_Texture_1(char *name, GRRLIB_texImg *tx) { void *data = NULL; int ret; SAFE_FREE(tx->data); ret = Load_Theme_Image(name, &data); if (ret == 0 && data) { tx_store(tx, GRRLIB_LoadTexture(data)); GRRLIB_SetHandle(tx, tx->w/2, tx->h/2); SAFE_FREE(data); if (tx->data) return true; } return false; } void Load_Theme_Texture(char *name, GRRLIB_texImg *tx, void *builtin) { if (Load_Theme_Texture_1(name, tx)) return; // failed, use builtin tx_store(tx, GRRLIB_LoadTexture(builtin)); GRRLIB_SetHandle(tx, tx->w/2, tx->h/2); } void GRRLIB_CopyTextureBlock(GRRLIB_texImg *src, int x, int y, int w, int h, GRRLIB_texImg *dest, int dx, int dy) { int ix, iy; u32 c; for (ix=0; ixw / 128; int tile_h = tx->h; if (tx->w <= 1024) return; // split to max 1024 width stripes GRRLIB_texImg tt; int i; int c_per_stripe; int nstripe; int stripe_w; // max number of characters per stripe c_per_stripe = 1024 / tile_w; // round down to a multiple of 4, so that the texture size // is a multiple of 4 as well. c_per_stripe = c_per_stripe >> 2 << 2; // number of stripes nstripe = (128 + c_per_stripe - 1) / c_per_stripe; // stripe width stripe_w = c_per_stripe * tile_w; GRRLIB_AllocTextureData(&tt, stripe_w, tile_h * nstripe); for (i=0; idata); *tx = tt; tt.data = NULL; } void GRRLIB_InitFont(GRRLIB_texImg *tx) { int tile_w; int tile_h; if (!tx->data) return; // detect font image type: 128x1 or 32x16 (512) if (tx->w / tx->h >= 32) { tile_w = tx->w / 128; tile_h = tx->h; // 128x1 font if (tx->w > 1024) { // split to max 1024 width stripes GRRLIB_RearrangeFont128(tx); } } else { // 32x16 font tile_w = tx->w / 32; tile_h = tx->h / 16; } //Gui_Console_Enable(); //printf("\n%d %d %d %d\n", tx->w, tx->h, tile_w, tile_h); //Wpad_WaitButtons(); // init tile GRRLIB_InitTileSet(tx, tile_w, tile_h, 0); GRRLIB_FlushTex(tx); } void GRRLIB_TrimTile(GRRLIB_texImg *tx, int maxn) { if (!tx || !tx->data) return; int n = tx->nbtilew * tx->nbtileh; if (n <= maxn) return; // roundup maxn to a full row int nh = (maxn + tx->nbtilew - 1) / tx->nbtilew; tx->h = tx->tileh * nh; int size = tx->w * tx->h * 4; // downsize tx->data = mem_realloc(tx->data, size); // re-init tile GRRLIB_InitTileSet(tx, tx->tilew, tx->tileh, 0); } void Gui_DumpUnicode(int xx, int yy) { wchar_t wc; char mb[32*6+1]; char line[10+32*6+1]; int i, k, len=0, count=0, y=0; int fh = tx_font.tileh; for (i=0; i<512; i++) { wc = i; k = wctomb(mb+len, wc); if (k < 1 || mb[len] == 0) { mb[len] = wc < 128 ? '!' : '?'; k = 1; } len += k; mb[len] = 0; count++; if (count >= 32) { sprintf(line, "%03x: %s |", (unsigned)i-31, mb); y = 10+(i/32*fh); Gui_Print2(xx+5, yy+y, line); len = 0; count = 0; } } for (i=0; ufont_map[i]; i+=2) { wc = ufont_map[i]; k = wctomb(mb+len, wc); if (k < 1 || mb[len] == 0) { mb[len] = wc < 128 ? '!' : '?'; k = 1; } len += k; mb[len] = 0; count++; if (count >= 32 || !ufont_map[i+2]) { sprintf(line, "map: %s |", mb); y += fh; Gui_Print2(xx+5, yy+y, line); len = 0; count = 0; } } } void Gui_TestUnicode() { if (CFG.debug != 2) return; GRRLIB_FillScreen(0x000000FF); Gui_DumpUnicode(0, 0); Gui_Print2(5, 440, gt("Press any button...")); Gui_Render(); Wpad_WaitButtons(); } void Gui_FillAscii(int xx, int yy, u32 color, int method) { char line[1000]; int y=0; int cols = 640 / tx_font.tilew - 1; int rows = 480 / tx_font.tileh - 2; int r, i; int c = 33; for (r=0; r= 128) c = 33; } line[i] = 0; y = 10 + r * tx_font.tileh; if (method == 0) GRRLIB_Printf(xx+5, yy+y, &tx_font, color, 1.0, "%s", line); else Gui_PrintEx2(xx+5, yy+y, &tx_font, color, 0, 0, line); } } void Gui_BenchText() { int i, m; int n = 10; for (m=0; m<2; m++) { GX_SetZMode (GX_FALSE, GX_NEVER, GX_TRUE); GRRLIB_FillScreen(0x000000FF); dbg_time_usec(); for (i=0; i> (i*8)) & 0xFF; x2 = (c2 >> (i*8)) & 0xFF; c = x1 + neg * x2; // range check, possible overflow if (c < 0) c = 0; if (c > 0xFF) c = 0xFF; color |= (c << (i*8)); } return color; } u32 color_multiply(u32 c1, u32 c2) { int i, x1, x2; u32 color = 0; u32 c; // each component for (i=0; i<4; i++) { x1 = (c1 >> (i*8)) & 0xFF; x2 = (c2 >> (i*8)) & 0xFF; c = x1 * x2 / 0xFF; // range check, just in case, but it shouldn't overflow if (c < 0) c = 0; if (c > 0xFF) c = 0xFF; color |= (c << (i*8)); } return color; } void font_color_multiply(FontColor *src, FontColor *dest, u32 color) { #define FC_MUL(X) dest->X = color_multiply(src->X, color) FC_MUL(color); // AA^4 for outline and shadow // because they are drawn 4 times color = color_multiply(color, color | 0xFFFFFF00); color = color_multiply(color, color | 0xFFFFFF00); FC_MUL(outline); FC_MUL(shadow); #undef FC_MUL } void Gui_PrintExx(float x, float y, GRRLIB_texImg *font, FontColor fc, float zoom, const char *str) { GRRLIB_Print3(x, y, font, fc.color, fc.outline, fc.shadow, zoom, str); } void Gui_PrintEx(int x, int y, GRRLIB_texImg *font, FontColor font_color, const char *str) { Gui_PrintExx(x, y, font, font_color, 1.0, str); } void Gui_PrintfEx(int x, int y, GRRLIB_texImg *font, FontColor font_color, char *fmt, ...) { char str[200]; va_list argp; va_start(argp, fmt); vsnprintf(str, sizeof(str), fmt, argp); va_end(argp); Gui_PrintEx(x, y, font, font_color, str); } // alignx: -1=left 0=centre 1=right // aligny: -1=top 0=centre 1=bottom void Gui_PrintAlignZ(float x, float y, int alignx, int aligny, GRRLIB_texImg *font, FontColor font_color, float zoom, char *str) { float xx = x, yy = y; int len; float w, h; len = con_len(str); w = len * font->tilew; h = font->tileh; w *= zoom; h *= zoom; if (alignx == 0) xx = x - w/2.0; else if (alignx > 0) xx = x - w; if (aligny == 0) yy = y - h/2.0; else if (aligny > 0) yy = y - h; // align to pixel for sharper text xx = (int)xx; yy = (int)yy; Gui_PrintExx(xx, yy, font, font_color, zoom, str); } void Gui_PrintAlign(int x, int y, int alignx, int aligny, GRRLIB_texImg *font, FontColor font_color, char *str) { Gui_PrintAlignZ(x, y, alignx, aligny, font, font_color, 1.0, str); } void Gui_Print2(int x, int y, const char *str) { Gui_PrintEx(x, y, &tx_font, CFG.gui_text2, str); } void Gui_Print(int x, int y, char *str) { Gui_PrintEx(x, y, &tx_font, CFG.gui_text, str); } void Gui_Printf(int x, int y, char *fmt, ...) { char str[200]; va_list argp; va_start(argp, fmt); vsnprintf(str, sizeof(str), fmt, argp); va_end(argp); Gui_Print(x, y, str); } void Gui_Print_Clock(int x, int y, FontColor font_color, int align) { if (CFG.clock_style == 0) return; GRRLIB_texImg *tx = &tx_font_clock; if (!tx->data) tx = &tx_font; Gui_PrintAlign(x, y, align, align, tx, font_color, get_clock_str(time(NULL))); } void Grx_Load_BG_Gui() { void *img_buf = NULL; // widescreen? if (CFG.widescreen && *CFG.bg_gui_wide) { img_buf = Gui_LoadBG(CFG.bg_gui_wide); } // or normal if (img_buf == NULL) { img_buf = Gui_LoadBG(CFG.bg_gui); } // or builtin if (img_buf == NULL) { img_buf = Gui_LoadBG_data(bg_gui); } // overlay int ret = -1; char path[200]; if (CFG.widescreen) { snprintf(D_S(path), "%s/bg_gui_over_w.png", CFG.theme_path); ret = Gui_OverlayBg(path, img_buf); } if (ret) { snprintf(D_S(path), "%s/bg_gui_over.png", CFG.theme_path); ret = Gui_OverlayBg(path, img_buf); } // texture GRRLIB_ReallocTextureData(&tx_bg, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); RGBA_to_4x4((u8*)img_buf, (u8*)tx_bg.data, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); SAFE_FREE(img_buf); } /** * Initilaizes all the common images (no cover, pointer, font, background...) * */ void Grx_Init() { if (!CFG.gui) return; int ret; GRRLIB_texImg tx_tmp; // detect theme change extern int cur_theme; static int last_theme = -1; bool theme_change = (last_theme != cur_theme); last_theme = cur_theme; // on cover_style change, need to reload noimage cover // (changing cover style invalidates cache and sets ccache_inv) if (!grx_init || ccache_inv) { // nocover image void *img = NULL; tx_tmp.data = NULL; ret = Gui_LoadCover_style((u8*)"", &img, true, CFG.cover_style, NULL); if (ret > 0 && img) { //tx_tmp = Gui_LoadTexture_RGBA8(img, COVER_WIDTH, COVER_HEIGHT, NULL, NULL); tx_tmp = Gui_LoadTexture_RGBA8(img, 0, 0, NULL, NULL); SAFE_FREE(img); } if (tx_tmp.data == NULL) { tx_tmp = Gui_LoadTexture_RGBA8(coverImg, 0, 0, NULL, NULL); } GRRLIB_TextureMEM2(&tx_nocover, &tx_tmp); //full nocover image tx_store(&tx_tmp, GRRLIB_LoadTexture(coverImg_full)); GRRLIB_TextureMEM2(&tx_nocover_full, &tx_tmp); } // on theme change we need to reload all gui resources if (!grx_init || theme_change) { // background gui Grx_Load_BG_Gui(); // background console GRRLIB_ReallocTextureData(&tx_bg_con, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); RGBA_to_4x4((u8*)bg_buf_rgba, (u8*)tx_bg_con.data, BACKGROUND_WIDTH, BACKGROUND_HEIGHT); Load_Theme_Texture("pointer.png", &tx_pointer, pointer); Load_Theme_Texture("hourglass.png", &tx_hourglass, hourglass); Load_Theme_Texture("favorite.png", &tx_star, star_icon); // Load the image file and initilise the tiles for gui font // default: font_uni.png if (!Load_Theme_Texture_1(CFG.gui_font, &tx_font)) { Load_Theme_Texture("font.png", &tx_font, gui_font); } GRRLIB_InitFont(&tx_font); // if font not found, tx_font_clock.data will be NULL Load_Theme_Texture_1("font_clock.png", &tx_font_clock); GRRLIB_InitFont(&tx_font_clock); GRRLIB_TrimTile(&tx_font_clock, 128); //store the hourglass image pasted into the noimage fullcover image tx_tmp = Gui_paste_into_fullcover(tx_hourglass.data, tx_hourglass.w, tx_hourglass.h, tx_nocover_full.data, tx_nocover_full.w, tx_nocover_full.h); GRRLIB_TextureMEM2(&tx_hourglass_full, &tx_tmp); } grx_init = 1; } void gui_tilt_pos(guVector *pos) { if (gui_style == GUI_STYLE_FLOW_Z) { // tilt pos float deg_max = 45.0; float deg = cam_f * cam_dir * deg_max; float rad = DegToRad(deg); float zf; Mtx rot; pos->x -= cam_look.x; pos->y -= cam_look.y; guMtxRotRad(rot, 'y', rad); guVecMultiply(rot, pos, pos); zf = (cam_z + pos->z) / cam_z; pos->x /= zf; pos->y /= zf; pos->x += cam_look.x; pos->y += cam_look.y; } } void tilt_cam(guVector *cam) { if (gui_style == GUI_STYLE_FLOW_Z) { // tilt cam float deg_max = 45.0; float deg = cam_f * cam_dir * deg_max; float rad = DegToRad(deg); Mtx rot; cam->x -= cam_look.x; cam->y -= cam_look.y; guMtxRotRad(rot, 'y', rad); guVecMultiply(rot, cam, cam); cam->x += cam_look.x; cam->y += cam_look.y; } } void Gui_set_camera(ir_t *ir, int enable) { float hold_w = 50.0, out = 64; // same as get_scroll() params float sx; if (ir) { // is out? // allow x out of screen by pointer size if (ir->sy < 0 || ir->sy > BACKGROUND_HEIGHT || ir->sx < -out || ir->sx > BACKGROUND_WIDTH+out) { if (cam_f > 0.0) cam_f -= 0.02; if (cam_f < 0.0) cam_f = 0.0; } else { sx = ir->sx; if (sx < 0.0) sx = 0.0; if (sx > 640.0) sx = 640.0; sx = sx - 320.0; // check hold position if (sx < 0) { cam_dir = -1.0; sx = -sx; } else { cam_dir = 1.0; } sx -= hold_w; if (sx < 0) sx = 0; cam_f = sx / (320.0 - hold_w); } } if (gui_style == GUI_STYLE_GRID || gui_style == GUI_STYLE_FLOW) { enable = 0; } if (enable == 0) { // 2D Mtx44 perspective; guOrtho(perspective,0, 480, 0, 640, 0, 300.0F); GX_LoadProjectionMtx(perspective, GX_ORTHOGRAPHIC); guMtxIdentity(GXmodelView2D); guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -50.0F); GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); } else { // (gui_style == GUI_STYLE_FLOW_Z) // 3D Mtx44 perspective; guPerspective(perspective, 45, 4.0/3.0, 0.1F, 2000.0F); GX_LoadProjectionMtx(perspective, GX_PERSPECTIVE); //guVector cam = {319.5F, 239.5F, -578.0F}; //guVector look = {319.5F, 239.5F, 0.0F}; guVector up = {0.0F, -1.0F, 0.0F}; guVector cam = cam_look; cam.z = cam_z; // tilt cam tilt_cam(&cam); guLookAt(GXmodelView2D, &cam, &up, &cam_look); GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); } if (gui_style == GUI_STYLE_FLOW_Z) { GX_SetZMode (GX_FALSE, GX_NEVER, GX_TRUE); } } void Gui_save_cover_style() { prev_cover_style = CFG.cover_style; prev_cover_height = COVER_HEIGHT; prev_cover_width = COVER_WIDTH; if (gui_style == GUI_STYLE_COVERFLOW) { if (CFG_cf_global.covers_3d) { if (CFG.cover_style != CFG_COVER_STYLE_FULL) { cfg_set_cover_style(CFG_COVER_STYLE_FULL); } } else { if (CFG.cover_style != CFG_COVER_STYLE_2D) { cfg_set_cover_style(CFG_COVER_STYLE_2D); } } } } /** * Resets the cover style to the previous one. Primarily used when * switching from full covers. */ void Gui_reset_previous_cover_style() { if (gui_style == GUI_STYLE_COVERFLOW) { //flip the cover style mode back to whatever it was cache_release_all(); cache_wait_idle(); cfg_set_cover_style(prev_cover_style); //set cover width and height back to original COVER_HEIGHT = prev_cover_height; COVER_WIDTH = prev_cover_width; } } void Gui_draw_background_alpha2(u32 color1, u32 color2) { Gui_set_camera(NULL, 0); //void GRRLIB_DrawSlice2(f32 xpos, f32 ypos, GRRLIB_texImg tex, float degrees, // float scaleX, f32 scaleY, u32 color1, u32 color2, // float x, float y, float w, float h) // top half GRRLIB_DrawSlice2(0, 0, tx_bg, 0, 1, 1, color1, color1, 0, 0, tx_bg.w, tx_bg.h / 2); // bottom half GRRLIB_DrawSlice2(0, tx_bg.h / 2, tx_bg, 0, 1, 1, color1, color2, 0, tx_bg.h / 2, tx_bg.w, tx_bg.h / 2); Gui_set_camera(NULL, 1); } void Gui_draw_background_alpha(u32 color) { Gui_set_camera(NULL, 0); GRRLIB_DrawImg(0, 0, &tx_bg, 0, 1, 1, color); Gui_set_camera(NULL, 1); } void Gui_draw_background() { Gui_draw_background_alpha(0xFFFFFFFF); } void Gui_draw_pointer(ir_t *ir) { // reset camera Gui_set_camera(NULL, 0); GX_SetZMode (GX_FALSE, GX_NEVER, GX_TRUE); // draw pointer GRRLIB_DrawImg(ir->sx - tx_pointer.w / 2, ir->sy - tx_pointer.h / 2, &tx_pointer, ir->angle, 1, 1, 0xFFFFFFFF); } void Repaint_ConBg(bool exiting) { int fb; void **xfb; GRRLIB_texImg tx; void *img_buf; xfb = _GRRLIB_GetXFB(&fb); _Video_SetFB(xfb[fb^1]); Video_Clear(COLOR_BLACK); if (exiting) return; // background Video_DrawBg(); // enable console if it was disabled till now Gui_Console_Enable(); // Cover if (CFG.covers == 0) return; if (gameCnt == 0) return; int state; GRRLIB_texImg *txp = cache_request_cover(gameSelected, CFG.cover_style, CC_FMT_C4x4, CC_PRIO_NONE, &state); if (txp) { if ((txp->w != COVER_WIDTH) || (txp->h != COVER_HEIGHT)) { txp = NULL; } } if (!txp) { extern void __Menu_ShowCover(); __Menu_ShowCover(); return; } tx = *txp; img_buf = memalign(32, tx.w * tx.h * 4); if (img_buf == NULL) return; C4x4_to_RGBA(tx.data, img_buf, tx.w, tx.h); DrawCoverImg(gameList[gameSelected].id, img_buf, tx.w, tx.h); //Video_CompositeRGBA(COVER_XCOORD, COVER_YCOORD, img_buf, tx.w, tx.h); //Video_DrawRGBA(COVER_XCOORD, COVER_YCOORD, img_buf, tx.w, tx.h); free(img_buf); } void Gui_Refresh_List() { cache_release_all(); cache_num_game(); if (gui_style == GUI_STYLE_COVERFLOW) { gameSelected = Coverflow_initCoverObjects(gameCnt, 0, true); //load the covers - alternate right and left cache_request_before_and_after(gameSelected, 5, 1); } else { //grid_init(page_gi); grid_init(0); } } void Gui_Action_Favorites() { reset_sort_default(); Switch_Favorites(!enable_favorite); Gui_Refresh_List(); } extern char action_string[40]; extern int action_alpha; void Gui_Sort_Set(int index, bool desc) { sortList_set(index, desc); Gui_Refresh_List(); sprintf(action_string, gt("Sort: %s-%s"), sortTypes[sort_index].name, (sort_desc) ? "DESC":"ASC"); action_alpha = 0xFF; } void Gui_Action_Sort() { if (sort_desc) { sort_desc = 0; if (sort_index == sortCnt - 1) sort_index = 0; else sort_index = sort_index + 1; } else { sort_desc = 1; } Gui_Sort_Set(sort_index, sort_desc); } void Gui_Action_Profile(int n) { if (CFG.current_profile == n) return; CFG.current_profile = n; if (CFG.current_profile >= CFG.num_profiles) CFG.current_profile = CFG.num_profiles - 1; if (CFG.current_profile < 0 ) CFG.current_profile = 0; reset_sort_default(); Switch_Favorites(CFG.profile_start_favorites[CFG.current_profile]); action_Theme_2(CFG.profile_theme[CFG.current_profile]); if (CFG.save_filter) { switch (CFG.profile_filter[CFG.current_profile]) { case FILTER_GENRE: filter_games_set(CFG.profile_filter[CFG.current_profile], CFG.profile_filter_genre[CFG.current_profile]); break; case FILTER_FEATURES: filter_games_set(CFG.profile_filter[CFG.current_profile], CFG.profile_filter_feature[CFG.current_profile]); break; case FILTER_CONTROLLER: filter_games_set(CFG.profile_filter[CFG.current_profile], CFG.profile_filter_controller[CFG.current_profile]); break; case FILTER_GAME_TYPE: filter_games_set(CFG.profile_filter[CFG.current_profile], CFG.profile_filter_gametype[CFG.current_profile]); break; case FILTER_SEARCH: strncpy(search_str, CFG.profile_search_string[CFG.current_profile], 100); filter_games_set(CFG.profile_filter[CFG.current_profile], CFG.profile_search_field[CFG.current_profile]); break; default: filter_games_set(CFG.profile_filter[CFG.current_profile], 0); break; } } Gui_Refresh_List(); sprintf(action_string, gt("Profile: %s"), CFG.profile_names[CFG.current_profile]); action_alpha = 0xFF; } int Gui_DoAction(int action, ir_t *ir) { if (action & CFG_BTN_REMAP) return 0; switch(action) { case CFG_BTN_NOTHING: return 0; case CFG_BTN_OPTIONS: case CFG_BTN_GLOBAL_OPS: return !CFG.disable_options; case CFG_BTN_GUI: case CFG_BTN_INSTALL: case CFG_BTN_REMOVE: case CFG_BTN_MAIN_MENU: case CFG_BTN_UNLOCK: case CFG_BTN_BOOT_DISC: case CFG_BTN_BOOT_GAME: case CFG_BTN_THEME: case CFG_BTN_FILTER: return 1; case CFG_BTN_REBOOT: case CFG_BTN_EXIT: case CFG_BTN_HBC: //exiting = true; __console_disable = 1; return -1; case CFG_BTN_SCREENSHOT: { char fn[200]; extern bool Save_ScreenShot(char *fn, int size); Save_ScreenShot(fn, sizeof(fn)); return 0; } case CFG_BTN_PROFILE: { int n = CFG.current_profile + 1; if (n >= CFG.num_profiles) n = 0; Gui_Action_Profile(n); } return 0; case CFG_BTN_FAVORITES: Gui_Action_Favorites(); return 0; case CFG_BTN_SORT: Gui_Action_Sort(); return 0; case CFG_BTN_RANDOM: //pick a random cover and scroll to it if (gui_style == GUI_STYLE_COVERFLOW) { int i, newIdx, ret, buttons; //this is needed so the easing slowdown doesn't occur in Coverflow_drawCovers extern int rotating_with_wiimote; newIdx = (rand() >> 16) % gameCnt; i = abs(gameSelected - newIdx); if (i > gameCnt/2) { //wrap around scrolling i = (newIdx > gameSelected) ? CF_TRANS_ROTATE_LEFT : CF_TRANS_ROTATE_RIGHT; } else { i = (newIdx < gameSelected) ? CF_TRANS_ROTATE_LEFT : CF_TRANS_ROTATE_RIGHT; } //init rotation while (1) { buttons = Wpad_GetButtons(); rotating_with_wiimote = 1; ret = Coverflow_init_transition(i, 100, gameCnt, false); if (ret > 0) gameSelected = ret; cache_release_all(); cache_request_before_and_after(gameSelected, 5, 1); Coverflow_drawCovers(ir, gameCnt, false); if (CFG.debug == 3) { GRRLIB_Printf(50, 360, &tx_font, CFG.gui_text.color, 1, "looking for: %d gameCnt: %d", newIdx, gameCnt); } Gui_Render(); if (ret == newIdx) break; if ((buttons & WPAD_BUTTON_B) || (buttons & WPAD_BUTTON_A)) break; } return 0; } else { return 1; } default: // Magic Word or Channel if ((action & 0xFF) < 'a') { __console_disable = 1; return -1; } else { return 1; } } } int Gui_Switch_Style(int new_style, int sub_style) { if (game_select >= 0) gameSelected = game_select; if (gui_style < GUI_STYLE_COVERFLOW) { if (new_style < GUI_STYLE_COVERFLOW) { // 1. from grid/flow to grid/flow if (new_style == gui_style && sub_style == grid_rows) { // nothing to do return 0; } grid_transit_style(new_style, sub_style); return 1; } else { // 2. from grid/flow to coverflow gui_style = new_style; CFG_cf_global.theme = sub_style; //Coverflow uses full covers ONLY // invalidate the cache and reload cache_release_all(); cache_wait_idle(); Gui_save_cover_style(); Cache_Invalidate(); Cache_Init(); Coverflow_Grx_Init(); gameSelected = Coverflow_initCoverObjects(gameCnt, gameSelected, false); //load the covers - alternate right and left cache_request_before_and_after(gameSelected, 5, 1); } } else { if (new_style == GUI_STYLE_COVERFLOW) { // 3. from coverflow to coverflow if (CFG_cf_global.theme == sub_style) { // nothing to do return 0; } CFG_cf_global.theme = sub_style; //setup the new coverflow style gameSelected = Coverflow_initCoverObjects(gameCnt, game_select, true); if (gameSelected == -1) { //fatal error - couldn't allocate memory gui_style = GUI_STYLE_GRID; grid_init(0); return 1; } Coverflow_init_transition(CF_TRANS_MOVE_TO_POSITION, 100, gameCnt, false); } else { // 4. from coverflow to grid/flow Gui_reset_previous_cover_style(); gui_style = new_style; grid_rows = sub_style; Cache_Invalidate(); Cache_Init(); grid_init(gameSelected); return 1; } } return 0; } int Gui_Shift_Style(int change) { int rows = grid_rows + change; int new_style = gui_style; if (game_select >= 0) gameSelected = game_select; if (CFG.gui_lock) { // if gui style locked, only allow to change number of rows if (gui_style < GUI_STYLE_COVERFLOW) { if (rows >= 1 && rows <= 4) { Gui_Switch_Style(gui_style, rows); return 1; } } } else { // transition gui style: // grid -> flow -> flow-z -> coverflow modes -> grid -> ... if (gui_style < GUI_STYLE_COVERFLOW) { // grid mode if (rows < 1 || rows > 4) { rows = grid_rows; new_style = gui_style + 1; } if (new_style < GUI_STYLE_COVERFLOW) { // grid - grid Gui_Switch_Style(new_style, rows); } else { // grid - coverflow Gui_Switch_Style(new_style, coverflow3d); } } else { // coverflow mode int subs = CFG_cf_global.theme + 1; if (subs >= 0 && subs <= carousel) { // coverflow - coverflow Gui_Switch_Style(gui_style, subs); } else { // coverflow - grid if (subs < 0) new_style = gui_style--; else new_style = GUI_STYLE_GRID; Gui_Switch_Style(new_style, grid_rows); return 1; } } } // CFG.gui_lock return 0; } /** * This is the main control loop for the 3D cover modes. */ int Gui_Mode() { int buttons = 0; int buttons_held = 0; ir_t ir; int fr_cnt = 0; bool exiting = false; bool suppressWiiPointerChecking = false; int ret = 0; //check for console mode if (CFG.gui == 0) return 0; memcheck(); //load all the commonly used images (background, pointers, etc) // although already called at startup it needs to be called again // in case theme changed Grx_Init(); //memcheck(); // setup gui style static int first_time = 1; if (first_time) { gui_style = CFG.gui_style; // CFG.gui_style has all the styles unified // split coverflow styles out: if (gui_style >= GUI_STYLE_COVERFLOW) { gui_style = GUI_STYLE_COVERFLOW; CFG_cf_global.theme = CFG.gui_style - GUI_STYLE_COVERFLOW; } grid_rows = CFG.gui_rows; } // start the cache thread if (Switch_Console_To_Gui()) { // cache error, return to console go_gui = 0; Switch_Gui_To_Console(false); return 0; } //initilaize the GRRLIB video subsystem Gui_Init(); if (gui_style == GUI_STYLE_COVERFLOW) { Coverflow_Grx_Init(); game_select = -1; gameSelected = Coverflow_initCoverObjects(gameCnt, gameSelected, false); //load the covers - alternate right and left cache_request_before_and_after(gameSelected, 5, 1); if (!first_time) { if (prev_cover_style == CFG_COVER_STYLE_3D) Coverflow_init_transition(CF_TRANS_MOVE_FROM_CONSOLE_3D, 100, gameCnt, false); else Coverflow_init_transition(CF_TRANS_MOVE_FROM_CONSOLE, 100, gameCnt, false); } } else { //allocate the grid and initialize the grid cover settings grid_init(gameSelected); game_select = -1; if (!first_time) { //fade in the grid grid_transition(1, page_gi); } } if (first_time) { first_time = 0; Gui_TestUnicode(); //Gui_BenchText(); } wgui_desk_init(); while (1) { restart: dbg_time_usec(); buttons = Wpad_GetButtons(); buttons_held = Wpad_Held(); Wpad_getIR(&ir); wgui_desk_handle(&ir, &buttons, &buttons_held); if (!go_gui) break; //---------------------- // HOME Button //---------------------- //if ((buttons & CFG.button_exit.mask) && Gui_DoAction(CFG.button_H)) { // /*if (CFG.home == CFG_HOME_SCRSHOT) { // char fn[200]; // extern bool Save_ScreenShot(char *fn, int size); // Save_ScreenShot(fn, sizeof(fn)); // } else { // exiting = true; // __console_disable = 1; // break; // }*/ // if (game_select >= 0) gameSelected = game_select; // break; //} //---------------------- // A Button //---------------------- if (loadGame) { buttons = buttonmap[MASTER][CFG.button_confirm.num]; loadGame = false; } if (buttons & CFG.button_confirm.mask) { if (game_select >= 0) { gameSelected = game_select; break; } } //---------------------- // B Button //---------------------- //if ((buttons & CFG.button_cancel.mask) && Gui_DoAction(CFG.button_B)) { // if (game_select >= 0) gameSelected = game_select; // break; //} //---------------------- // dpad RIGHT //---------------------- if (buttons & WPAD_BUTTON_RIGHT) { if (gui_style == GUI_STYLE_COVERFLOW) { ret = Coverflow_init_transition(CF_TRANS_ROTATE_RIGHT, 0, gameCnt, true); if (ret > 0) { game_select = ret; cache_release_all(); cache_request_before_and_after(game_select, 5, 1); } suppressWiiPointerChecking = true; } else { if (grid_page_change(1)) goto restart; } } else if (buttons_held & WPAD_BUTTON_RIGHT) { if (gui_style == GUI_STYLE_COVERFLOW) { ret = Coverflow_init_transition(CF_TRANS_ROTATE_RIGHT, 100, gameCnt, true); if (ret > 0) { game_select = ret; cache_release_all(); cache_request_before_and_after(game_select, 5, 1); } suppressWiiPointerChecking = true; } } //---------------------- // dpad LEFT //---------------------- if (buttons & WPAD_BUTTON_LEFT) { if (gui_style == GUI_STYLE_COVERFLOW) { ret = Coverflow_init_transition(CF_TRANS_ROTATE_LEFT, 0, gameCnt, true); if (ret > 0) { game_select = ret; cache_release_all(); cache_request_before_and_after(game_select, 5, 1); } suppressWiiPointerChecking = true; } else { if (grid_page_change(-1)) goto restart; } } else if (buttons_held & WPAD_BUTTON_LEFT) { if (gui_style == GUI_STYLE_COVERFLOW) { ret = Coverflow_init_transition(CF_TRANS_ROTATE_LEFT, 100, gameCnt, true); if (ret > 0) { game_select = ret; cache_release_all(); cache_request_before_and_after(game_select, 5, 1); } suppressWiiPointerChecking = true; } } //---------------------- // dpad UP //---------------------- if (buttons & WPAD_BUTTON_UP) { if (gui_style == GUI_STYLE_COVERFLOW) { game_select = Coverflow_flip_cover_to_back(true, 2); } else { if (Gui_Shift_Style(1)) goto restart; } } //---------------------- // dpad DOWN //---------------------- if (buttons & WPAD_BUTTON_DOWN) { if (Gui_Shift_Style(-1)) goto restart; } // need to return to menu for timeout if (CFG.admin_lock) { if (buttons & CFG.button_other.mask) { if (game_select >= 0) gameSelected = game_select; goto return_to_console; } } //---------------------- // (CFG) button //---------------------- int i; for (i = 4; i < MAX_BUTTONS; i++) { if ((buttons & buttonmap[MASTER][i]) && (ret = Gui_DoAction(*(&CFG.button_M + (i - 4)), &ir))) { if (ret < 0) exiting = true; else if (game_select >= 0) gameSelected = game_select; goto return_to_console; } } //---------------------- // check for other wiimote events //---------------------- if (gui_style == GUI_STYLE_FLOW || gui_style == GUI_STYLE_FLOW_Z) { // scroll flow style grid_get_scroll(&ir); } else if (gui_style == GUI_STYLE_COVERFLOW) { if (!suppressWiiPointerChecking) game_select = Coverflow_process_wiimote_events(&ir, gameCnt); else suppressWiiPointerChecking = false; } //if we should load a game then do //that instead of drawing the next frame if (loadGame || suppressCoverDrawing) { suppressCoverDrawing = false; goto restart; } //draw the covers if (gui_style == GUI_STYLE_COVERFLOW) { game_select = Coverflow_drawCovers(&ir, gameCnt, true); } else { //draw the background Gui_draw_background(); grid_calc(); game_select = grid_update_all(&ir); Gui_set_camera(&ir, 1); grid_draw(game_select); // title grid_print_title(game_select); } wgui_desk_render(&ir, &buttons); int us = dbg_time_usec(); if (CFG.debug == 3) { GRRLIB_Printf(20, 50, &tx_font, 0xFF00FFFF, 1, "%4d ms:%6.2f", fr_cnt, (float)us/1000.0); } /* Gui_Printf(50, 390, "r x:%6.1f y:%6.1f v: %d %d a:%6.1f", ir.ax, ir.ay, ir.raw_valid, ir.state, ir.angle); Gui_Printf(50, 410, "s x:%6.1f y:%6.1f v: %d", ir.sx, ir.sy, ir.smooth_valid); Gui_Printf(50, 430, "b x:%6.1f y:%6.1f v: %d", ir.x, ir.y, ir.valid); */ //draw_Cache(); //GRRLIB_DrawImg(0, 50, tx_font, 0, 1, 1, 0xFFFFFFFF); // entire font //Gui_FillAscii(10, 10, 0xffffffff, 1); Gui_draw_pointer(&ir); //GRRLIB_Rectangle(fr_cnt % 640, 0, 5, 15, 0x000000FF, 1); Gui_Render(); fr_cnt++; } return_to_console: if (gui_style == GUI_STYLE_COVERFLOW) { // this is for when transitioning from coverflow to Console... if (!exiting) { if (prev_cover_style == CFG_COVER_STYLE_3D) Coverflow_init_transition(CF_TRANS_MOVE_TO_CONSOLE_3D, 100, gameCnt, false); else Coverflow_init_transition(CF_TRANS_MOVE_TO_CONSOLE, 100, gameCnt, false); } } else { // this is for when transitioning from Grid to Console... //transition(-1, page_i*grid_covers); if (!exiting) grid_transition(-1, page_gi); } wgui_desk_close(); Switch_Gui_To_Console(exiting); return buttons; } int Switch_Console_To_Gui() { __console_flush(0); VIDEO_Flush(); VIDEO_WaitVSync(); Gui_save_cover_style(); gui_mode = 1; __console_disable = 1; // reinit cache if it was invalidated int ret = Cache_Init(); memcheck(); return ret; } void Switch_Gui_To_Console(bool exiting) { cache_release_all(); //reset to the previous style before leaving Gui_reset_previous_cover_style(); Con_Clear(); __console_flush(0); Repaint_ConBg(exiting); // restore original framebuffer _Video_SyncFB(); _GRRLIB_SetFB(0); gui_mode = 0; if (!exiting) __console_disable = 0; } void Gui_Close() { Cache_Close(); if (CFG.gui == 0) return; if (!grr_init) return; dbg_printf("Gui_Close\n"); __console_flush(0); VIDEO_Flush(); VIDEO_WaitVSync(); _GRRLIB_Exit(); SAFE_FREE(tx_pointer.data); SAFE_FREE(tx_font.data); Coverflow_Close(); grr_init = 0; }