// by usptactical #include #include #include #include #include #include #include #include #include #include #include #include #include "coverflow.h" #include "cfg.h" #include "gui.h" #include "cache.h" #include "wpad.h" #include "my_GRRLIB.h" #include "xml.h" #include "gettext.h" //defines for the mouseover detection #define MOUSEOVER_COVER_OFFSCREEN 0xFFFFFFFF //defines for default background alpha levels #define BACKGROUND_REFLECTION_ALPHA 0xFFFFFF44 #define BACKGROUND_REFLECTION_ALPHA2 0xFFFFFFAA //defines for how many Cover structs to allocate #define MAX_COVERFLOW_COVERS 10 #define MAX_COVERFLOW_COVERS_TOTAL 12 //maximum length of the drawn title text #define TITLE_MAX 54 //position at which the wiimote starts scrolling right/left on x axis #define WIIMOTE_SIDE_SCROLL_WIDTH 100 //defines used for setting final cover positioning during transitions #define COVERPOS_FLIP_TO_BACK 0 #define COVERPOS_CENTER_THEME 1 #define COVERPOS_CONSOLE_2D 2 #define COVERPOS_CONSOLE_3D 3 #define COVERPOS_GAME_LOAD 4 //defines for fading the background (for flip to back) #define BACKGROUND_FADE_NONE 0 #define BACKGROUND_FADE_DARK 1 #define BACKGROUND_FADE_LIGHT 2 //easing type used for the last rotation in a right/left transition #define EASING_TYPE_SLOW 3 #define EASING_TYPE_LINEAR 0 #define DML_MAGIC 0x444D4C00 #define DML_MAGIC_HDD DML_MAGIC + 1 extern struct discHdr *gameList; extern s32 gameCnt; extern bool loadGame; extern bool suppressCoverDrawing; //AA extern struct GRRLIB_texImg aa_texBuffer[4]; bool coverflow_test_grid = false; struct settings_cf_global CFG_cf_global; struct settings_cf_theme CFG_cf_theme[CF_THEME_NUM]; //struct for the cover coords and color levels typedef struct CoverPos { float x,y,z; // screen co-ordinates float xrot, yrot, zrot; // rotation int alpha; // alpha level of cover u32 reflection_bottom; // color of the bottom portion of the reflection (bottom of the cover box) u32 reflection_top; // color of the top portion of the reflection (top of the cover box) } CoverPos; //struct to store the game cover properties typedef struct Cover { CoverPos themePos; CoverPos startPos; CoverPos endPos; CoverPos currentPos; int gi; // game index int state; // current loading state of the cover image bool selected; // set to true if cover is being pointed at u32 stencil_color; // the stencil cover (for pointer-over detection) int hidden; // is cover is hidden? GRRLIB_texImg tx; // cover image data } Cover; Cover coverCoords_center; Cover coverCoords_left[MAX_COVERFLOW_COVERS_TOTAL]; Cover coverCoords_right[MAX_COVERFLOW_COVERS_TOTAL]; extern unsigned char cover_top[]; extern unsigned char cover_front[]; extern unsigned char cover_side[]; extern unsigned char coverImg_full[]; GRRLIB_texImg *tx_cover_top; GRRLIB_texImg *tx_cover_front; GRRLIB_texImg *tx_cover_side; GRRLIB_texImg tx_nocover_full_CMPR; GRRLIB_texImg tx_hourglass_full; GRRLIB_texImg tx_screenshot; GXTexObj texCoverTop; GXTexObj texCoverFront; GXTexObj texCoverSide; WPADData wpad_data; static int background_fade_status = 0; static int grx_cover_init = 0; static int cover_init = 0; bool showingFrontCover = true; static bool spinCover_dpad_used = false; u32 selectedColor; //vars for the floating cover functionality f32 float_speed_increment = 0.03; f32 float_max_xrot = 5; //10 f32 float_max_yrot = 5; //10 f32 float_max_zrot = 3; //3 f32 float_xrot; f32 float_yrot; f32 float_zrot; bool float_xrot_up = true; bool float_yrot_up = false; bool float_zrot_up = true; static int rotation_start_index = 0; int rotating_with_wiimote = 0; Mtx GXview2D; /** * Retrieves the current data for wiimote 1 * @return void */ #if 0 void getWiiMoteInfo() { u32 ext; //Extension type //u32 ret=0; //remote probe return WPAD_ScanPads(); ret=WPAD_Probe(WPAD_CHAN_0,&ext); //probe remote 1 with extension WPADData *Data = WPAD_Data(WPAD_CHAN_0); //store data from remote 1 wpad_data = *Data; WPAD_IR(WPAD_CHAN_0, &wpad_data.ir); //get IR data WPAD_Orientation(WPAD_CHAN_0, &wpad_data.orient); //get rotation data WPAD_GForce(WPAD_CHAN_0, &wpad_data.gforce); //get "speed" data WPAD_Accel(WPAD_CHAN_0, &wpad_data.accel); //get accelerometer data WPAD_Expansion(WPAD_CHAN_0, &wpad_data.exp); //get expansion data } #endif /** * Initilaizes all the common cover images (top, side, front, back) * @return void */ void Coverflow_Grx_Init() { GRRLIB_texImg tx_tmp; showingFrontCover = true; if (!grx_cover_init) { tx_cover_top = GRRLIB_LoadTexture(cover_top); tx_cover_front = GRRLIB_LoadTexture(cover_front); tx_cover_side = GRRLIB_LoadTexture(cover_side); GX_InitTexObj(&texCoverTop, tx_cover_top->data, tx_cover_top->w, tx_cover_top->h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_InitTexObj(&texCoverFront, tx_cover_front->data, tx_cover_front->w, tx_cover_front->h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_InitTexObj(&texCoverSide, tx_cover_side->data, tx_cover_side->w, tx_cover_side->h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); if (CFG.gui_compress_covers) { //store a CMPR version of the full cover tx_tmp = Gui_LoadTexture_CMPR(coverImg_full, 0, 0, NULL, NULL); GRRLIB_TextureMEM2(&tx_nocover_full_CMPR, &tx_tmp); } } grx_cover_init = 1; } /** * Frees image resources * @return void */ void Coverflow_Close() { if (grx_cover_init) { GRRLIB_FREE_TEX(tx_cover_top); GRRLIB_FREE_TEX(tx_cover_front); GRRLIB_FREE_TEX(tx_cover_side); } } /** * Sets the image load state, and if the image is in the cache it adds it to * the cover struct. * * @param *cover Cover struct representing a game * @return void */ void update_cover_state2(Cover *cover, int cstyle) { int gi = cover->gi; //make sure this is a valid cover index if (gi < 0) return; //set the current image state for this cover GRRLIB_texImg *tx; int fmt = CC_COVERFLOW_FMT; tx = cache_request_cover(gi, cstyle, fmt, CC_PRIO_MED, &cover->state); if (cover->state == CS_PRESENT) { cover->tx = *tx; } else if (cover->state == CS_IDLE) { cover->tx = tx_hourglass_full; } else if (cover->state == CS_LOADING) { cover->tx = tx_hourglass_full; } else { // CS_MISSING if (CFG.gui_compress_covers) cover->tx = tx_nocover_full_CMPR; else cover->tx = tx_nocover_full; } } void update_cover_state(Cover *cover) { update_cover_state2(cover, CFG_COVER_STYLE_FULL); } /** * Checks the loading status of the covers. * @return void */ void Coverflow_update_state() { int i; struct Cover *cover; //center cover if (showingFrontCover) { update_cover_state(&coverCoords_center); } else { update_cover_state2(&coverCoords_center, CFG_COVER_STYLE_HQ_OR_FULL); } //check left side for (i=0; i < CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers + 1; i++) { cover = &coverCoords_left[i]; update_cover_state(cover); } //check right side for (i=0; i < CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers + 1; i++) { cover = &coverCoords_right[i]; update_cover_state(cover); } } /** * Sets the projection matrix for 2D display * @return void */ void set2DProjectionMatrix() { Mtx44 GXprojection2D; guMtxIdentity(GXmodelView2D); guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -50.0F); GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); guOrtho(GXprojection2D, 0, 480, 0, 640, 0, 300.0F); GX_LoadProjectionMtx(GXprojection2D, GX_ORTHOGRAPHIC); } /** * Used to set the camera position * @param aaStep int position in the array to store the created tex * @return void */ void set_camera() { //set the view guVector cam = {CFG_cf_theme[CFG_cf_global.theme].cam_pos_x, CFG_cf_theme[CFG_cf_global.theme].cam_pos_y, CFG_cf_theme[CFG_cf_global.theme].cam_pos_z}, up = {0.0F, 1.0F, 0.0F}, look = {CFG_cf_theme[CFG_cf_global.theme].cam_look_x, CFG_cf_theme[CFG_cf_global.theme].cam_look_y, CFG_cf_theme[CFG_cf_global.theme].cam_look_z}; guLookAt(GXview2D, &cam, &up, &look); } //Easing routines from http://www.robertpenner.com/easing/ // t = time // c = change in position // d = duration // b = beginning position float linearOut(float t, float b , float c, float d) { return c*t/d + b; } float easeOutQuad(float t, float b , float c, float d) { t /= d; return -c * t*(t-2) + b; } float easeOutCubic(float t, float b , float c, float d) { t = t/d - 1; return c*(t*t*t + 1) + b; } float easeOutQuart(float t, float b , float c, float d) { t = t/d - 1; return -c * (t*t*t*t - 1) + b; } float easeOutQuint(float t, float b , float c, float d) { t = t/d - 1; return c*(t*t*t*t*t + 1) + b; //Quint } float easeOutExpo(float t, float b , float c, float d) { return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b; } float ease_x(int type, float t, float b, float c, float d) { switch (type) { default: case 0: return linearOut(t, b, c, d); case 1: return easeOutQuad(t, b, c, d); case 2: return easeOutCubic(t, b, c, d); case 3: return easeOutQuart(t, b, c, d); case 4: return easeOutQuint(t, b, c, d); case 5: return easeOutExpo(t, b, c, d); } } /** * Method used to calculate the new position when moving an object. Can be used for moving on any axis (x,y,z) * E.g. moving a cover from the right side to the center. * The basic equation is: * current pos = starting point - ((starting point - end point) * index / number of total frames) * * @param startPos f32 representing the original starting point of the object * @param endPos f32 representing the ending point (where you want the object to ultimately end up). * @param index int representing the current index in the loop * @param totalFrames int representing the total number of frames in your loop * @param ease_type int representing the type of easing to use in the calculation * @return f32 next position */ f32 calculateNewPosition(f32 startPos, f32 endPos, int index, int totalFrames, int ease_type) { if (index >= totalFrames || totalFrames==0 || startPos==endPos) return endPos; switch (ease_type) { case 0: return linearOut(index, startPos, endPos - startPos, totalFrames); case 1: return easeOutQuad(index, startPos, endPos - startPos, totalFrames); case 2: return easeOutCubic(index, startPos, endPos - startPos, totalFrames); case 3: return easeOutQuart(index, startPos, endPos - startPos, totalFrames); case 4: return easeOutQuint(index, startPos, endPos - startPos, totalFrames); case 5: return easeOutExpo(index, startPos, endPos - startPos, totalFrames); } return endPos; } /** * Method used to calculate the new alpha level when moving a color. * * @param startPos u32 representing the original starting color of the object * @param endPos u32 representing the ending color (where you want the color to ultimately end up). * @param index int representing the current index in the loop * @param totalFrames into representing the total number of frames in your loop * @param ease_type int representing the type of easing to use in the calculation * @return u32 next color in the iteration */ u32 calculateNewColor(u32 startPos, u32 endPos, int index, int totalFrames, int ease_type) { u32 color; int a, a1, a2; int i; if (index > totalFrames || totalFrames==0 || startPos==endPos) return endPos; // each component color = 0; for (i=0; i<4; i++) { a1 = (startPos >> (i*8)) & 0xFF; a2 = (endPos >> (i*8)) & 0xFF; a = ease_x(ease_type, index, a1, a2 - a1, totalFrames); // range check, just in case.. if (a < 0) a = 0; if (a > 0xFF) a = 0xFF; color |= (a << (i*8)); } return color; } /** * Initializes the cover image layout in the current CFG_cf_theme[CFG_cf_global.theme]. * @param coverCount total number of covers * @param index represents the cover index of the center cover * @return int of the selected cover */ int setCoverIndexing(int coverCount, int index) { int i, img, selectedCover; img = index; //set the center to the first cover if the index is bad if (img < 1 || img >= coverCount) img = 0; selectedCover = img; //set the right covers coverCoords_center.gi = img; img++; if (img >= coverCount) img = 0; for (i=0; i < CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers + 1; i++) { coverCoords_right[i].gi = img; img++; if (img >= coverCount) img = 0; } //set the left covers img = selectedCover-1; if (img < 0) img = coverCount - 1; if (img < 0) img = 0; for (i=0; i < CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers + 1; i++) { coverCoords_left[i].gi = img; img--; if (img < 0) img = coverCount - 1; if (img < 0) img = 0; } return selectedCover; } /** * Converts degrees to radians: * angle = index * ((Math.PI * 2) / numOfItems); * @param degree the degree to convert * @return f32 representing the radian */ f32 degToRad (f32 degree) { return (degree * M_PI) / 180.f; } /** * Initializes a cover positioned to the left of center * @param *cover Cover struct object of the cover to set up * @param index represents the cover's index in the coverCoords_left array * @return void */ void setCoverPosition_Left(CoverPos *cover, int index) { f32 angle_deg, angle_rad, radius; int alpha; cover->x = CFG_cf_theme[CFG_cf_global.theme].cover_left_xpos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_left_x; cover->y = CFG_cf_theme[CFG_cf_global.theme].cover_left_ypos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_left_y; cover->z = CFG_cf_theme[CFG_cf_global.theme].cover_left_zpos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_left_z; cover->xrot = CFG_cf_theme[CFG_cf_global.theme].cover_left_xrot; cover->yrot = CFG_cf_theme[CFG_cf_global.theme].cover_left_yrot; cover->zrot = CFG_cf_theme[CFG_cf_global.theme].cover_left_zrot; if (CFG_cf_theme[CFG_cf_global.theme].cover_rolloff_y != 0) { angle_deg = CFG_cf_theme[CFG_cf_global.theme].cover_rolloff_y * index; radius = CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_left_x * index; //convert rolloff degree to radians angle_rad = degToRad(angle_deg); // x = Math.cos(mc.angle) * radiusX + centerX; // y = Math.sin(mc.angle) * radiusY + centerY; cover->x += cosf(angle_rad) * radius; cover->z -= sinf(angle_rad) * radius; cover->yrot += angle_deg; } else { cover->x += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_left_x * index); cover->y += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_left_y * index); cover->z += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_left_z * index); } cover->alpha = coverCoords_center.themePos.alpha - CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff * (index+1); if (cover->alpha < 0) { cover->alpha = 0; cover->reflection_bottom = 0x00000000; cover->reflection_top = 0x00000000; } else { alpha = (CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom & 0xFF) - (CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff/2) * (index+1); if (alpha <= 0) { cover->reflection_bottom = 0x00000000; } else { cover->reflection_bottom = ((CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom & 0xFFFFFF00) | alpha); } //cover->reflection_bottom = CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom; alpha = (CFG_cf_theme[CFG_cf_global.theme].reflections_color_top & 0xFF) - (CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff/2) * (index+1); if (alpha <= 0) { cover->reflection_top = 0x00000000; } else { cover->reflection_top = ((CFG_cf_theme[CFG_cf_global.theme].reflections_color_top & 0xFFFFFF00) | alpha); } //cover->reflection_top = CFG_cf_theme[CFG_cf_global.theme].reflections_color_top; } } /** * Initializes a cover positioned to the right of center * @param *cover CoverPos struct object of the cover to set up * @param index represents the cover's index in the coverCoords_right array * @return void */ void setCoverPosition_Right(CoverPos *cover, int index) { f32 angle_deg, angle_rad, radius; int alpha; cover->x = CFG_cf_theme[CFG_cf_global.theme].cover_right_xpos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_right_x; cover->y = CFG_cf_theme[CFG_cf_global.theme].cover_right_ypos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_right_y; cover->z = CFG_cf_theme[CFG_cf_global.theme].cover_right_zpos + CFG_cf_theme[CFG_cf_global.theme].cover_distance_from_center_right_z; cover->xrot = CFG_cf_theme[CFG_cf_global.theme].cover_right_xrot; cover->yrot = CFG_cf_theme[CFG_cf_global.theme].cover_right_yrot; cover->zrot = CFG_cf_theme[CFG_cf_global.theme].cover_right_zrot; if (CFG_cf_theme[CFG_cf_global.theme].cover_rolloff_y != 0) { angle_deg = CFG_cf_theme[CFG_cf_global.theme].cover_rolloff_y * index * -1; radius = CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_right_x * index; //convert rolloff degree to radians angle_rad = degToRad(angle_deg); // x = Math.cos(mc.angle) * radiusX + centerX; // y = Math.sin(mc.angle) * radiusY + centerY; cover->x += cosf(angle_rad) * radius; cover->z -= sinf(angle_rad) * radius; cover->yrot += angle_deg; } else { cover->x += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_right_x * index); cover->y += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_right_y * index); cover->z += (CFG_cf_theme[CFG_cf_global.theme].cover_distance_between_covers_right_z * index); } cover->alpha = coverCoords_center.themePos.alpha - CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff * (index+1); if (cover->alpha < 0) { cover->alpha = 0; cover->reflection_bottom = 0x00000000; cover->reflection_top = 0x00000000; } else { alpha = (CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom & 0xFF) - (CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff/2) * (index+1); if (alpha <= 0) { cover->reflection_bottom = 0x00000000; } else { cover->reflection_bottom = ((CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom & 0xFFFFFF00) | alpha); } //cover->reflection_bottom = CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom; alpha = (CFG_cf_theme[CFG_cf_global.theme].reflections_color_top & 0xFF) - (CFG_cf_theme[CFG_cf_global.theme].alpha_rolloff/2) * (index+1); if (alpha <= 0) { cover->reflection_top = 0x00000000; } else { cover->reflection_top = ((CFG_cf_theme[CFG_cf_global.theme].reflections_color_top & 0xFFFFFF00) | alpha); } //cover->reflection_top = CFG_cf_theme[CFG_cf_global.theme].reflections_color_top; } } /** * Method to set GX Position and Color */ void drawPosCol(f32 x, f32 y, f32 z, u32 c) { GX_Position3f32(x, y, z); GX_Color1u32(c); } /** * Method to set GX Position, Color and Texture coords */ void drawPosColTex(f32 x, f32 y, f32 z, u32 c, f32 tx, f32 ty) { GX_Position3f32(x, y, z); GX_Color1u32(c); GX_TexCoord2f32(tx, ty); } /** * Method to draw a flat 2D cover image with perspective-based (3D) viewpoint. * * @param tex cover image to draw * @param xpos x axis position for the image * @param ypos y axis position for the image * @param zpos z axis position for the image * @param xrot degrees to rotate the image on the x axis. For example a value of 90 will rotate it 90 degrees so it would appear flat on it's cover to the viewer. * @param yrot degrees to rotate the image on the y axis. For example a value of 90 will rotate it 90 degrees on it's side so the front will be facing right to the viewer * @param zrot degrees to rotate the image. For example a value of 90 will rotate it 90 degrees counter-clockwise * @param color the color to make the cover * @param reflectionColorBottom the color (including alpha) of the bottom portion of the reflection (bottom of the cover). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorTop the color (including alpha) of the top portion of the reflection (top of the cover). 255 will be a solid image. 0 will be fully transparent. * @param isFavorite bool represents if the favorite image should be drawn over the cover * @return void */ void draw_2dcover_image(GRRLIB_texImg *tex, f32 xpos, f32 ypos, f32 zpos, f32 xrot, f32 yrot, f32 zrot, u32 color, u32 reflectionColorBottom, u32 reflectionColorTop, bool isFavorite) { Mtx44 GXprojection2D; //Mtx GXview2D; Mtx GXmodel2D; Mtx GXModelTemp; //Mtx GXmodelView2D; GXTexObj texObj; f32 width, height; guVector xaxis = (guVector) {1, 0, 0}; guVector yaxis = (guVector) {0, 1, 0}; guVector zaxis = (guVector) {0, 0, 1}; //set the view set_camera(); guMtxIdentity(GXmodel2D); GX_LoadTexMtxImm(GXmodel2D, GX_TEXMTX0, GX_MTX2x4); //get the objects size //width = COVER_WIDTH * 0.0625; //height = COVER_HEIGHT * 0.0625; width = 10.0; height = 14.0; //set rotation if (xrot != 0) { guMtxRotAxisDeg(GXModelTemp, &xaxis, xrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (yrot != 0) { guMtxRotAxisDeg(GXModelTemp, &yaxis, yrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (zrot != 0) { guMtxRotAxisDeg(GXModelTemp, &zaxis, zrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } // set the XYZ position guMtxTransApply(GXmodel2D, GXmodel2D, xpos, ypos, zpos); guMtxConcat (GXview2D, GXmodel2D, GXmodelView2D); // load the modelview matrix into matrix memory GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); if (CFG.widescreen) { guPerspective(GXprojection2D, 45, 1.778F, 0.1F, 500.0F); } else { guPerspective(GXprojection2D, 45, (f32)4/3, 0.1F, 500.0F); } GX_LoadProjectionMtx(GXprojection2D, GX_PERSPECTIVE); GX_SetZMode(GX_ENABLE, GX_ALWAYS, GX_TRUE); //set blend mode GX_SetColorUpdate(GX_ENABLE); GX_SetAlphaUpdate(GX_ENABLE); //don't enable this or images look crappy - disables aa // GX_InitTexObjLOD(&texObjects[index], GX_NEAR, GX_NEAR, 0, 0, 0, GX_FALSE, GX_FALSE, GX_ANISO_1); GX_InitTexObj(&texObj, tex->data, tex->w, tex->h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); //front blank cover GX_LoadTexObj(&texCoverFront, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, height, 0, color, 0.0f, 0.0f); drawPosColTex(width, height, 0, color, 1.0f, 0.0f); drawPosColTex(width, -height, 0, color, 1.0f, 1.0f); drawPosColTex(-width, -height, 0, color, 0.0f, 1.0f); GX_End(); //front cover image GX_LoadTexObj(&texObj, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, height-0.5, 0, color, 0.0f, 0.0f); drawPosColTex(width-0.5, height-0.5, 0, color, 1.0f, 0.0f); drawPosColTex(width-0.5, -height+0.5, 0, color, 1.0f, 1.0f); drawPosColTex(-width, -height+0.5, 0, color, 0.0f, 1.0f); GX_End(); //draw the favorites star if (isFavorite) { //calculate the size f32 star_scale = .125; f32 starw = tx_star.w * star_scale; f32 starh = tx_star.h * star_scale; //init the texture GXTexObj texStar; GX_InitTexObj(&texStar, tx_star.data, tx_star.w, tx_star.h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_LoadTexObj(&texStar, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width-starw, height, 0, color, 0.0f, 0.0f); drawPosColTex(width, height, 0, color, 1.0f, 0.0f); drawPosColTex(width, height-starh, 0, color, 1.0f, 1.0f); drawPosColTex(width-starw, height-starh, 0, color, 0.0f, 1.0f); GX_End(); } GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); if (reflectionColorBottom > 0 || reflectionColorTop > 0) { //Draw the reflection image upside down. Set the RGBA color //near the bottom of the cover (top of the reflection) to the passed //in alpha level. The RGBA for the lowest part of the reflection is //set to zero, which gives us a fade-to-black appearance. GX_LoadTexObj(&texObj, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, -height-1, 0, reflectionColorBottom, 0.0f, 1.0f); drawPosColTex(width, -height-1, 0, reflectionColorBottom, 1.0f, 1.0f); drawPosColTex(width, -height*2.5, 0, reflectionColorTop, 1.0f, 0.0f); drawPosColTex(-width, -height*2.5, 0, reflectionColorTop, 0.0f, 0.0f); GX_End(); } GX_LoadPosMtxImm (GXview2D, GX_PNMTX0); //set TevOp to GX_PASSCLR so that we get the color's alpha level GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); //reset the viewpoint to 2D set2DProjectionMatrix(); } /** * Method to draw cover image with perspective-based (3D) viewpoint. * * @param tex cover image to draw * @param xpos x axis position for the image * @param ypos y axis position for the image * @param zpos z axis position for the image * @param xrot degrees to rotate the image on the x axis. For example a value of 90 will rotate it 90 degrees so it would appear flat on it's cover to the viewer. * @param yrot degrees to rotate the image on the y axis. For example a value of 90 will rotate it 90 degrees on it's side so the front will be facing right to the viewer * @param zrot degrees to rotate the image. For example a value of 90 will rotate it 90 degrees counter-clockwise * @param color the color to make the cover (where the game image is) * @param edgecolor the color to make the boxcover edges * @param isFavorite bool represents if the favorite image should be drawn over the cover * @return void */ // lod bias: at -1.0 looks best, lower values get slow, higher loose quality float lod_bias_a[] = { -2.0, -1.5, -1.0, -0.5, -0.3, 0, +0.5, +1 }; int lod_bias_idx = 2; void draw_fullcover_image(GRRLIB_texImg *tex, f32 xpos, f32 ypos, f32 zpos, f32 xrot, f32 yrot, f32 zrot, u32 color, u32 edgecolor, bool isFavorite) { Mtx44 GXprojection2D; //Mtx GXview2D; Mtx GXmodel2D; Mtx GXModelTemp; //Mtx GXmodelView2D; GXTexObj texCoverImage; //cover width and height f32 width = 10.0; f32 height = 14.0; //fullcover tex positioning f32 front_start = 0.525; f32 spine_start = 0.475; //distance between front and back covers f32 COVER_BOX_DEPTH = 2.0; //depth of the edge f32 COVER_EDGE_DEPTH = 0.3; //depth of side panel (closest / farthest wrt the viewpoint) f32 COVER_SIDE_NEAR_DEPTH = COVER_BOX_DEPTH - COVER_EDGE_DEPTH; f32 COVER_SIDE_FAR_DEPTH = COVER_EDGE_DEPTH; guVector xaxis = (guVector) {1, 0, 0}; guVector yaxis = (guVector) {0, 1, 0}; guVector zaxis = (guVector) {0, 0, 1}; set_camera(); guMtxIdentity(GXmodel2D); GX_LoadTexMtxImm(GXmodel2D, GX_TEXMTX0, GX_MTX2x4); //get the objects size //width = COVER_WIDTH * 0.0625; //height = COVER_HEIGHT * 0.0625; //set rotation if (xrot != 0) { guMtxRotAxisDeg(GXModelTemp, &xaxis, xrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (yrot != 0) { guMtxRotAxisDeg(GXModelTemp, &yaxis, yrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (zrot != 0) { guMtxRotAxisDeg(GXModelTemp, &zaxis, zrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } // set the XYZ position guMtxTransApply(GXmodel2D, GXmodel2D, xpos, ypos, zpos); guMtxConcat (GXview2D, GXmodel2D, GXmodelView2D); // load the modelview matrix into matrix memory GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); if (CFG.widescreen) { guPerspective(GXprojection2D, 45, 1.778F, 0.1F, 500.0F); } else { guPerspective(GXprojection2D, 45, (f32)4/3, 0.1F, 500.0F); } GX_LoadProjectionMtx(GXprojection2D, GX_PERSPECTIVE); GX_SetZMode(GX_ENABLE, GX_ALWAYS, GX_TRUE); //GX_SetZMode (GX_ENABLE, GX_LEQUAL, GX_TRUE); //set blend mode GX_SetColorUpdate(GX_ENABLE); GX_SetAlphaUpdate(GX_ENABLE); int tx_fmt = GX_TF_RGBA8; if (tex->tex_format) tx_fmt = tex->tex_format; GX_InitTexObj(&texCoverImage, tex->data, tex->w, tex->h, tx_fmt, GX_CLAMP, GX_CLAMP, GX_FALSE); //don't enable this or images look crappy - disables aa //GX_InitTexObjLOD(&texCoverImage, GX_NEAR, GX_NEAR, 0, 0, 0, GX_FALSE, GX_FALSE, GX_ANISO_1); if (tex->tex_lod) { // mipmap float lod_bias = lod_bias_a[lod_bias_idx]; GX_InitTexObjLOD(&texCoverImage, GX_LIN_MIP_LIN, GX_LINEAR, 0.f, // lod min (float)tex->tex_lod, // lod max lod_bias, // lod bias GX_FALSE, GX_FALSE, // edge lod GX_ANISO_1); //GX_ANISO_2 GX_ANISO_4); // _1 seems sharper } //------------------------------------------------- // draw the edges //------------------------------------------------- GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetCullMode (GX_CULL_BACK); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); //top front edge GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width, height, COVER_BOX_DEPTH, edgecolor); drawPosCol(-width, height, COVER_BOX_DEPTH, edgecolor); GX_End(); //top front corner GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(width, height, COVER_BOX_DEPTH, edgecolor); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //right front edge (opening) GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, height, COVER_BOX_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width, -height, COVER_BOX_DEPTH, edgecolor); GX_End(); //bottom front corner (opening) GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(width, -height, COVER_BOX_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //bottom front edge GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, -height, COVER_BOX_DEPTH, edgecolor); drawPosCol(width, -height, COVER_BOX_DEPTH, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //------------------------------------------- //top right edge (between top and opening) GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //bottom right edge (between bottom and opening) GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //------------------------------------------- //top left edge (between top and spine) GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(-width, height, 0.0f, edgecolor); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, height, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //top left edge (between top and spine) GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, height, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //top left edge (between top and spine) GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, height, COVER_BOX_DEPTH, edgecolor); drawPosCol(-width, height, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //bottom left edge (between bottom and spine) GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(-width, -height, 0.0f, edgecolor); drawPosCol(-width, -height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //bottom left edge (between bottom and spine) GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, -height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, -height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //bottom left edge (between bottom and spine) GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(-width, -height, COVER_SIDE_NEAR_DEPTH, edgecolor); drawPosCol(-width, -height, COVER_BOX_DEPTH, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor); GX_End(); //------------------------------------------- //top back edge GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(-width, height, 0.0f, edgecolor); drawPosCol(width, height, 0.0f, edgecolor); GX_End(); //top back corner GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(width, height, 0.0f, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //right back edge GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width + COVER_EDGE_DEPTH, height, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width, height, 0.0f, edgecolor); drawPosCol(width, -height, 0.0f, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //bottom back corner GX_Begin(GX_TRIANGLES, GX_VTXFMT0, 3); drawPosCol(width, -height, 0.0f, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //bottom back edge GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, -height, 0.0f, edgecolor); drawPosCol(-width, -height, 0.0f, edgecolor); drawPosCol(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); drawPosCol(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor); GX_End(); //-------------------------------- // draw generic no cover image top and right side (cover opening) //-------------------------------- //top GX_LoadTexObj(&texCoverTop, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_FRONT); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor, 0.0f, 0.0f); drawPosColTex(width, height + COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor, 1.0f, 0.0f); drawPosColTex(width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor, 1.0f, 1.0f); drawPosColTex(-width, height + COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor, 0.0f, 1.0f); GX_End(); //right - cover opening GX_LoadTexObj(&texCoverSide, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width + COVER_EDGE_DEPTH, height, COVER_SIDE_NEAR_DEPTH, edgecolor, 0.0f, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, height, COVER_SIDE_FAR_DEPTH, edgecolor, 1.0f, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_FAR_DEPTH, edgecolor, 1.0f, 1.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height, COVER_SIDE_NEAR_DEPTH, edgecolor, 0.0f, 1.0f); GX_End(); //bottom GX_LoadTexObj(&texCoverTop, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor, 0.0f, 0.0f); drawPosColTex(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_NEAR_DEPTH, edgecolor, 1.0f, 0.0f); drawPosColTex(width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor, 1.0f, 1.0f); drawPosColTex(-width, -height - COVER_EDGE_DEPTH, COVER_SIDE_FAR_DEPTH, edgecolor, 0.0f, 1.0f); GX_End(); //-------------------------------- // draw cover image //-------------------------------- //Wrap the full cover GX_LoadTexObj(&texCoverImage, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); //fullcover back GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width, height, 0.0f, color, 0.0f, 0.0f); drawPosColTex(-width, height, 0.0f, color, spine_start, 0.0f); drawPosColTex(-width, -height, 0.0f, color, spine_start, 1.0f); drawPosColTex(width, -height, 0.0f, color, 0.0f, 1.0f); GX_End(); //fullcover spine GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, height, 0.0f, color, spine_start, 0.0f); drawPosColTex(-width, height, COVER_BOX_DEPTH, color, front_start, 0.0f); drawPosColTex(-width, -height, COVER_BOX_DEPTH, color, front_start, 1.0f); drawPosColTex(-width, -height, 0.0f, color, spine_start, 1.0f); GX_End(); //fullcover front GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width, height, COVER_BOX_DEPTH, color, front_start, 0.0f); drawPosColTex(width, height, COVER_BOX_DEPTH, color, 1.0f, 0.0f); drawPosColTex(width, -height, COVER_BOX_DEPTH, color, 1.0f, 1.0f); drawPosColTex(-width, -height, COVER_BOX_DEPTH, color, front_start, 1.0f); GX_End(); //-------------------------------- // favorites star //-------------------------------- if (isFavorite) { //calculate the size f32 star_scale = .125; f32 starw = tx_star.w * star_scale; f32 starh = tx_star.h * star_scale; //init the texture GXTexObj texStar; GX_InitTexObj(&texStar, tx_star.data, tx_star.w, tx_star.h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_LoadTexObj(&texStar, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width-starw, height, COVER_BOX_DEPTH, color, 0.0f, 0.0f); drawPosColTex(width, height, COVER_BOX_DEPTH, color, 1.0f, 0.0f); drawPosColTex(width, height-starh, COVER_BOX_DEPTH, color, 1.0f, 1.0f); drawPosColTex(width-starw, height-starh, COVER_BOX_DEPTH, color, 0.0f, 1.0f); GX_End(); } GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_LoadPosMtxImm (GXview2D, GX_PNMTX0); //set TevOp to GX_PASSCLR so that we get the color's alpha level GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); //reset the viewpoint to 2D set2DProjectionMatrix(); } /** * Method to draw cover image reflection with perspective-based (3D) viewpoint. * * @param tex cover image to draw * @param xpos x axis position for the image * @param ypos y axis position for the image * @param zpos z axis position for the image * @param xrot degrees to rotate the image on the x axis. For example a value of 90 will rotate it 90 degrees so it would appear flat on it's cover to the viewer. * @param yrot degrees to rotate the image on the y axis. For example a value of 90 will rotate it 90 degrees on it's side so the front will be facing right to the viewer * @param zrot degrees to rotate the image. For example a value of 90 will rotate it 90 degrees counter-clockwise * @param reflectionColorBottom the color (including alpha) of the bottom portion of the reflection (bottom of the cover). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorTop the color (including alpha) of the top portion of the reflection (top of the cover). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorBottomEdge the color (including alpha) of the bottom portion of the reflection (bottom of the boxcover). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorTopEdge the color (including alpha) of the top portion of the reflection (top of the boxcover). 255 will be a solid image. 0 will be fully transparent. * @param isFavorite bool represents if the favorite image should be drawn over the cover * @return void */ void draw_fullcover_image_reflection(GRRLIB_texImg *tex, f32 xpos, f32 ypos, f32 zpos, f32 xrot, f32 yrot, f32 zrot, u32 reflectionColorBottom, u32 reflectionColorTop, u32 reflectionColorBottomEdge, u32 reflectionColorTopEdge, bool isFavorite) { Mtx44 GXprojection2D; //Mtx GXview2D; Mtx GXmodel2D; Mtx GXModelTemp; //Mtx GXmodelView2D; GXTexObj texCoverImage; //cover width and height f32 width = 10.0; f32 height = 14.0; //fullcover tex positioning f32 front_start = 0.525; f32 spine_start = 0.475; //distance between the cover and its reflection f32 COVER_REFLECTION_DISTANCE = 2.0; //distance between front and back covers f32 COVER_BOX_DEPTH = 2.0; //depth of the edge f32 COVER_EDGE_DEPTH = 0.3; guVector xaxis = (guVector) {1, 0, 0}; guVector yaxis = (guVector) {0, 1, 0}; guVector zaxis = (guVector) {0, 0, 1}; set_camera(); guMtxIdentity(GXmodel2D); GX_LoadTexMtxImm(GXmodel2D, GX_TEXMTX0, GX_MTX2x4); //get the objects size //width = COVER_WIDTH * 0.0625; //height = COVER_HEIGHT * 0.0625; //set rotation if (xrot != 0) { guMtxRotAxisDeg(GXModelTemp, &xaxis, xrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (yrot != 0) { guMtxRotAxisDeg(GXModelTemp, &yaxis, yrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (zrot != 0) { guMtxRotAxisDeg(GXModelTemp, &zaxis, zrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } // set the XYZ position guMtxTransApply(GXmodel2D, GXmodel2D, xpos, ypos, zpos); guMtxConcat (GXview2D, GXmodel2D, GXmodelView2D); // load the modelview matrix into matrix memory GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); if (CFG.widescreen) { guPerspective(GXprojection2D, 45, 1.778F, 0.1F, 500.0F); } else { guPerspective(GXprojection2D, 45, (f32)4/3, 0.1F, 500.0F); } GX_LoadProjectionMtx(GXprojection2D, GX_PERSPECTIVE); //GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); GX_SetZMode (GX_ENABLE, GX_LEQUAL, GX_TRUE); //GX_SetZMode(GX_ENABLE, GX_ALWAYS, GX_TRUE); //set blend mode GX_SetColorUpdate(GX_ENABLE); GX_SetAlphaUpdate(GX_ENABLE); int tx_fmt = GX_TF_RGBA8; if (tex->tex_format) tx_fmt = tex->tex_format; GX_InitTexObj(&texCoverImage, tex->data, tex->w, tex->h, tx_fmt, GX_CLAMP, GX_CLAMP, GX_FALSE); if (tex->tex_lod) { // mipmap float lod_bias = lod_bias_a[lod_bias_idx]; GX_InitTexObjLOD(&texCoverImage, GX_LIN_MIP_LIN, GX_LINEAR, 0.f, // lod min (float)tex->tex_lod, // lod max lod_bias, // lod bias GX_FALSE, GX_FALSE, // edge lod GX_ANISO_1); //GX_ANISO_2 GX_ANISO_4); // _1 seems sharper } //-------------------------------- // Reflection //-------------------------------- if (reflectionColorBottom > 0 || reflectionColorTop > 0) { //Draw the reflection image upside down. Set the RGBA color //near the bottom of the cover (top of the reflection) to the passed //in alpha level. The RGBA for the lowest part of the reflection is //set to zero, which gives us a fade-to-black appearance. //right side - cover opening GX_LoadTexObj(&texCoverSide, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottomEdge, 0.0f, 1.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0, reflectionColorBottomEdge, 1.0f, 1.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, 0.0, reflectionColorTopEdge, 1.0f, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTopEdge, 0.0f, 0.0f); GX_End(); //bottom GX_LoadTexObj(&texCoverTop, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0, reflectionColorBottomEdge, 0.0f, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0, reflectionColorBottomEdge, 1.0f, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottomEdge, 1.0f, 1.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottomEdge, 0.0f, 1.0f); GX_End(); //draw the game cover image GX_LoadTexObj(&texCoverImage, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); //fullcover back GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorBottom, 0.0f, 1.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorBottom, spine_start, 1.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height *2.5 - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorTop, spine_start, 0.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height *2.5 - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorTop, 0.0f, 0.0f); GX_End(); //front cover reflection GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottom, front_start, 1.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottom, 1.0f, 1.0f); drawPosColTex(width + COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTop, 1.0f, 0.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTop, front_start, 0.0f); GX_End(); //left - cover spine GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorBottom, spine_start, 1.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorBottom, front_start, 1.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTop, front_start, 0.0f); drawPosColTex(-width - COVER_EDGE_DEPTH, -height*2.5 - COVER_REFLECTION_DISTANCE, 0.0f, reflectionColorTop, spine_start, 0.0f); GX_End(); } //-------------------------------- // favorites star //-------------------------------- if (isFavorite) { //calculate the size f32 starw = tx_star.w * .125; f32 starh = tx_star.h * .062; //init the texture GXTexObj texStar; GX_InitTexObj(&texStar, tx_star.data, tx_star.w, tx_star.h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); GX_LoadTexObj(&texStar, GX_TEXMAP0); GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE); GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_SetCullMode (GX_CULL_BACK); GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosColTex(width-starw, -height*2.5 + starh, COVER_BOX_DEPTH, reflectionColorTop, 0.0f, 1.0f); drawPosColTex(width, -height*2.5 + starh, COVER_BOX_DEPTH, reflectionColorTop, 1.0f, 1.0f); drawPosColTex(width, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTop, 1.0f, 0.0f); drawPosColTex(width-starw, -height*2.5 - COVER_REFLECTION_DISTANCE, COVER_BOX_DEPTH, reflectionColorTop, 0.0f, 0.0f); GX_End(); } GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0); GX_LoadPosMtxImm (GXview2D, GX_PNMTX0); //set TevOp to GX_PASSCLR so that we get the color's alpha level GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); //reset the viewpoint to 2D set2DProjectionMatrix(); } /** * Method that draws the passed in Cover in the specified color. This is used by the * capture_cover_positions() method for the cover mouseover detection. * @param *cover CoverPos object to draw * @param color the color to make the entire cover object. (e.g. 0x888888FF) * @return void */ void draw_phantom_cover (CoverPos *cover, u32 color) { Mtx44 GXprojection2D; Mtx GXview2D; Mtx GXmodel2D; Mtx GXModelTemp; //Mtx GXmodelView2D; f32 width, height; f32 COVER_BOX_DEPTH = 1.7; guVector xaxis = (guVector) {1, 0, 0}; guVector yaxis = (guVector) {0, 1, 0}; guVector zaxis = (guVector) {0, 0, 1}; //set the view guVector cam = {CFG_cf_theme[CFG_cf_global.theme].cam_pos_x, CFG_cf_theme[CFG_cf_global.theme].cam_pos_y, CFG_cf_theme[CFG_cf_global.theme].cam_pos_z}, up = {0.0F, 1.0F, 0.0F}, look = {CFG_cf_theme[CFG_cf_global.theme].cam_look_x, CFG_cf_theme[CFG_cf_global.theme].cam_look_y, CFG_cf_theme[CFG_cf_global.theme].cam_look_z}; guLookAt(GXview2D, &cam, &up, &look); if (CFG.widescreen) { guPerspective(GXprojection2D, 45, 1.778F, 0.1F, 500.0F); } else { guPerspective(GXprojection2D, 45, (f32)4/3, 0.1F, 500.0F); } GX_LoadProjectionMtx(GXprojection2D, GX_PERSPECTIVE); GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetVtxDesc(GX_VA_TEX0, GX_NONE); guMtxIdentity(GXmodel2D); //get the objects size width = 10.0; height = 14.0; //set rotation if (cover->xrot != 0) { guMtxRotAxisDeg(GXModelTemp, &xaxis, cover->xrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (cover->yrot != 0) { guMtxRotAxisDeg(GXModelTemp, &yaxis, cover->yrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } if (cover->zrot != 0) { guMtxRotAxisDeg(GXModelTemp, &zaxis, cover->zrot); guMtxConcat (GXmodel2D, GXModelTemp, GXmodel2D); } // set the XYZ position guMtxTransApply(GXmodel2D, GXmodel2D, cover->x, cover->y, cover->z); guMtxConcat (GXview2D, GXmodel2D, GXmodelView2D); // load the modelview matrix into matrix memory GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0); //top GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, height, COVER_BOX_DEPTH, color); drawPosCol(width, height, COVER_BOX_DEPTH, color); drawPosCol(width, height, 0.0f, color); drawPosCol(-width, height, 0.0f, color); GX_End(); //right - cover opening GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, height, COVER_BOX_DEPTH, color); drawPosCol(width, height, 0.0f, color); drawPosCol(width, -height, 0.0f, color); drawPosCol(width, -height, COVER_BOX_DEPTH, color); GX_End(); //back GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(width, height, 0.0f, color); drawPosCol(-width, height, 0.0f, color); drawPosCol(-width, -height, 0.0f, color); drawPosCol(width, -height, 0.0f, color); GX_End(); //spine GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, height, 0.0f, color); drawPosCol(-width, height, COVER_BOX_DEPTH, color); drawPosCol(-width, -height, COVER_BOX_DEPTH, color); drawPosCol(-width, -height, 0.0f, color); GX_End(); //front GX_Begin(GX_QUADS, GX_VTXFMT0, 4); drawPosCol(-width, height, COVER_BOX_DEPTH, color); drawPosCol(width, height, COVER_BOX_DEPTH, color); drawPosCol(width, -height, COVER_BOX_DEPTH, color); drawPosCol(-width, -height, COVER_BOX_DEPTH, color); GX_End(); GX_LoadPosMtxImm (GXview2D, GX_PNMTX0); GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); GX_SetVtxDesc (GX_VA_TEX0, GX_NONE); } /** * Method that sets the stencil colors * @return void */ void set_cover_stencil_colors() { int i; for (i=1; i<=CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers; i++) { coverCoords_left[i-1].stencil_color = GRRLIB_GetColor((u8)i, 0xFF, 0xFF, 0xFF); coverCoords_right[i-1].stencil_color = GRRLIB_GetColor((u8)255-i, 0xFF, 0xFF, 0xFF); } coverCoords_center.stencil_color = MOUSEOVER_COVER_OFFSCREEN; } /** * Method that draws each cover in a different color and then takes a snapshot of the buffer * @return void */ void capture_cover_positions() { int i; if (tx_screenshot.data == NULL) { // first time, allocate // only 8 bits per pixel (R8) int src_size = 128 * 128; // 16384 tx_screenshot.data = LARGE_alloc(src_size); tx_screenshot.w = 128; tx_screenshot.h = 128; } GRRLIB_prepareStencil(); //draw the covers with different colors for (i=CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers-1; i>=0; i--) { draw_phantom_cover(&coverCoords_left[i].currentPos, coverCoords_left[i].stencil_color); draw_phantom_cover(&coverCoords_right[i].currentPos, coverCoords_right[i].stencil_color); } draw_phantom_cover(&coverCoords_center.currentPos, coverCoords_center.stencil_color); GRRLIB_renderStencil_buf(&tx_screenshot); } /** * Method that updates the Cover.selected attribute of all the covers. The * selectedIndex param is used to tell which cover should be set to true - all * others will be marked false. * * Valid selectedIndex values: * Center cover index = 0 * Left covers are < 0 -> so the left cover next to the center is -1 * Right covers are > 0 -> so the right cover next to the center is 1 * * @param selectedIndex the index of the cover that should be marked as selected * @return void */ void set_selected_state(int selectedIndex) { int i; for (i=0; i 0 && selectedIndex == i + 1) coverCoords_right[i].selected = true; else coverCoords_right[i].selected = false; } if (selectedIndex == 0) coverCoords_center.selected = true; else coverCoords_center.selected = false; } /** * Method that returns the game index (gi) of the currently selected cover * based on the Cover.selected attribute * * @return int representing game index */ int get_selected_cover_index() { int i, selection; for (i=0; isx, ir->sy, tx_screenshot); selectedColor = GRRLIB_GetColor((u8)i, 0xFF, 0xFF, 0xFF); if (selectedColor == coverCoords_center.stencil_color) { set_selected_state(0); selected_gi = coverCoords_center.gi; goto out; } for (i=0; i bdiff) ? rdiff : bdiff; int diff = (gdiff > diff1) ? gdiff : diff1; diff = (diff > 0) ? diff : 0; //subtract diff from each color and add val r = r - diff + (rv * neg); r = (r > 255) ? 255 : ((r < 0) ? 0 : r); g = g - diff + (gv * neg); g = (g > 255) ? 255 : ((g < 0) ? 0 : g); b = b - diff + (bv * neg); b = (b > 255) ? 255 : ((b < 0) ? 0 : b); return ((u8)r << 24) | ((u8)g << 16) | ((u8)b << 8) | A(col2); } /** * Method that calculates the boxcover edge color * * @param gi the game image id number * @param selected boolean that represents if the cover should be dimmed (selected=false) or normal (selected=true) * @param alpha the alpha level of the cover. 255 will be a solid image. 0 will be fully transparent. * @param color the color (including alpha) of the game image * @param reflectionColorBottom the color (including alpha) of the bottom portion of the reflection (bottom of the game image). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorTop the color (including alpha) of the top portion of the reflection (top of the game image). 255 will be a solid image. 0 will be fully transparent. * @param edgecolor the color (including alpha) of the boxcover * @param reflectionBottomEdge the color (including alpha) of the bottom portion of the reflection (bottom of the boxcover). * @param reflectionTopEdge the color (including alpha) of the top portion of the reflection (top of the boxcover). * @return void */ void get_boxcover_edge_color(int gi, bool selected, u8 alpha, u32 color, u32 reflectionColorBottom, u32 reflectionColorTop, u32 *edgecolor, u32 *reflectionBottomEdge, u32 *reflectionTopEdge) { u32 col; bool dbColorFound = false; char *gameid; gameid = (char*)gameList[gi].id; //check xml database for color if (xml_getCaseColor(&col, (u8 *)gameid)) { dbColorFound = true; col |= alpha; } else { col = color; } //New Super Mario Bros if (strncmp(gameid, "SMN", 3) == 0) col = 0xFF000000 | alpha; //GameCube Games if(gameList[gi].magic == DML_MAGIC || gameList[gi].magic == DML_MAGIC_HDD) col = 0x32323200 | alpha; if (selected) { *edgecolor = col; *reflectionBottomEdge = addU32Value(col, reflectionColorBottom, 0x11111100, 1); *reflectionTopEdge = addU32Value(col, reflectionColorTop, 0x11111100, 1); } else { if (dbColorFound) *edgecolor = addU32Value(col, col, 0x22222200, -1); else *edgecolor = col; *reflectionBottomEdge = addU32Value(col, reflectionColorBottom, 0x11111100, -1); *reflectionTopEdge = addU32Value(col, reflectionColorTop, 0x11111100, -1); } } /** * Method draws a cover image. Used when the cover structure isn't fully populated (in rotation loops, etc.) * and you need to pass in every value. * * @param tex image of the game cover * @param xpos x axis position for the image * @param ypos y axis position for the image * @param zpos z axis position for the image * @param xrot degrees to rotate the image on the x axis. For example a value of 90 will rotate it 90 degrees so it would appear flat on it's cover to the viewer. * @param yrot degrees to rotate the image on the y axis. For example a value of 90 will rotate it 90 degrees on it's side so the front will be facing right to the viewer * @param zrot degrees to rotate the image. For example a value of 90 will rotate it 90 degrees counter-clockwise * @param alpha the alpha level of the cover. 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorBottom the color (including alpha) of the bottom portion of the reflection (bottom of the game image). 255 will be a solid image. 0 will be fully transparent. * @param reflectionColorTop the color (including alpha) of the top portion of the reflection (top of the game image). 255 will be a solid image. 0 will be fully transparent. * @param draw3DCover boolean to determine if we should we draw the 3D cover object * @param favorite boolean that represents if the favorites image should be drawn on the cover * @param selected boolean that represents if the cover should be dimmed (selected=false) or normal (selected=true) * @param drawReflection if true the cover reflection is drawn, else the cover itself * @param gi the game image id number * @return void */ void draw_cover_image(GRRLIB_texImg *tex, f32 xpos, f32 ypos, f32 zpos, f32 xrot, f32 yrot, f32 zrot, u8 alpha, u32 reflectionColorBottom, u32 reflectionColorTop, bool draw3DCover, bool favorite, bool selected, bool drawReflection, int gi) { u32 color, edgecolor, reflectionBottom, reflectionTop, reflectionBottomEdge, reflectionTopEdge; //is this cover selected? if (selected) { //light up selected game image color = 0xFFFFFF00 | alpha; reflectionBottom = color_add(reflectionColorBottom, 0x11111100, 1); reflectionTop = color_add(reflectionColorTop, 0x11111100, 1); } else { //dim not selected game image color = 0xDDDDDD00 | alpha; reflectionBottom = color_add(reflectionColorBottom, 0x11111100, -1); reflectionTop = color_add(reflectionColorTop, 0x11111100, -1); } //boxcover color get_boxcover_edge_color(gi, selected, alpha, color, reflectionColorBottom, reflectionColorTop, &edgecolor, &reflectionBottomEdge, &reflectionTopEdge); if (draw3DCover) { if (drawReflection) draw_fullcover_image_reflection(tex, xpos, ypos, zpos, xrot, yrot, zrot, reflectionBottom, reflectionTop, reflectionBottomEdge, reflectionTopEdge, favorite); else draw_fullcover_image(tex, xpos, ypos, zpos, xrot, yrot, zrot, color, edgecolor, favorite); } else { draw_2dcover_image(tex, xpos, ypos, zpos, xrot, yrot, zrot, color, reflectionBottom, reflectionTop, favorite); } } /** * Method that fades the background * @return void */ void fadeBackground() { int background_alpha = 0; switch (background_fade_status) { case BACKGROUND_FADE_DARK: if (CFG_cf_global.transition == CF_TRANS_FLIP_TO_BACK && CFG_cf_global.frameCount > 0 && CFG_cf_global.frameIndex <= CFG_cf_global.frameCount) { background_alpha = calculateNewPosition(0, CFG_cf_global.screen_fade_alpha, CFG_cf_global.frameIndex, CFG_cf_global.frameCount, EASING_TYPE_LINEAR); } else { background_alpha = CFG_cf_global.screen_fade_alpha; } break; case BACKGROUND_FADE_LIGHT: if (CFG_cf_global.transition == CF_TRANS_FLIP_TO_BACK && CFG_cf_global.frameCount > 0 && CFG_cf_global.frameIndex <= CFG_cf_global.frameCount) { background_alpha = calculateNewPosition(CFG_cf_global.screen_fade_alpha, 0, CFG_cf_global.frameIndex, CFG_cf_global.frameCount, EASING_TYPE_LINEAR); } else { background_fade_status = BACKGROUND_FADE_NONE; background_alpha = 0; } break; default: case BACKGROUND_FADE_NONE: return; } if (background_alpha > 0 && background_alpha <= 255) { GRRLIB_FillScreen(0x00000000 | background_alpha); } } /** * Method that gets the next position in an arc. * parabola calculation: * y = a(x-h)2+k * a < 0 means opening is down (shaped like n) * h = distance to vertex * k = height * for Excel: vertex = -0.8 * (POWER(B3 - (-10), 2)) + 10 * * @param a represents the opening - usually generated from the getAparam() method * @param height represents the height of the arc. So if you want the vertex to stop at 10 on the x axis, pass in a 10 * @param vertex represents the distance to the vertex from the starting point * @param index represents the current index in your drawing loop * @return f32 representing your next position */ f32 getArcPos(f32 a, f32 height, f32 vertex, f32 index) { return a * (pow(index - vertex, 2)) + height; } /** * Method that gets the A param for the getArcPos() method * parabola calculation: * y = a(x-h)2+k * a < 0 means opening is down (shaped like n) * h = distance to vertex * k = height * * @param height represents the height of the arc. So if you want the vertex to stop at 10 on the x axis, pass in a 10 * @param vertex represents the distance to the vertex from the starting point * @param finalIndexPos your last index value in your drawing loop (max loop value) * @param finalArcPos represents where you want to end on the straight axis - so if you're arcing from left to right on the * screen and you want the arc to be on the y axis, you pass in where you want to end on the x axis. * @return f32 representing the A value */ f32 getAparam(f32 height, f32 vertex, f32 finalIndexPos, f32 finalArcPos) { return (-height + finalArcPos) / (pow(finalIndexPos - vertex, 2)); } extern char action_string[40]; extern int action_alpha; /** * Draws the selected cover's title * * @param selectedCover int representing the currently selected cover index * @return void */ void Coverflow_draw_title(int selectedCover, int xpos, ir_t *ir) { f32 title_y, title_x; char gameTitle[TITLE_MAX] = ""; static time_t last_time = 0; bool do_clock = false; FontColor font_color = CFG.gui_text2; time_t t = 0; //game title stub..... if (ir->smooth_valid || CFG_cf_global.frameCount || !CFG.clock_style) { last_time = 0; L_title: if (action_alpha) { font_color.color = (font_color.color & 0xFFFFFF00) | action_alpha; if (action_alpha > 0) action_alpha -= 3; if (action_alpha < 0) action_alpha = 0; last_time = 0; strncpy(gameTitle, action_string, TITLE_MAX); } else { if (!gameCnt) { strcpy(gameTitle, gt("No games found!")); } else if (selectedCover < 0 || selectedCover >= gameCnt) { sprintf(gameTitle, "error %d", selectedCover); } else { snprintf(gameTitle, TITLE_MAX, "%s", get_title(&gameList[selectedCover])); } } } else { // clock t = time(NULL); // wait 5 seconds before showing clock if (last_time == 0) { last_time = t; goto L_title; } if (t - last_time < 5) goto L_title; do_clock = true; } //if xpos>0 then we are overriding the theme's settings if (xpos > 0) { title_x = xpos; } else { //Get x pos -> -1 means center it if (CFG_cf_theme[CFG_cf_global.theme].title_text_xpos == -1) title_x = (BACKGROUND_WIDTH/2) - (strlen(gameTitle)*(tx_font.tilew))/2; else title_x = CFG_cf_theme[CFG_cf_global.theme].title_text_xpos; } //Get y pos -> -1 means center it if (CFG_cf_theme[CFG_cf_global.theme].title_text_ypos == -1) { title_y = BACKGROUND_HEIGHT/2; } else { title_y = CFG_cf_theme[CFG_cf_global.theme].title_text_ypos; } //check if we're showing the back cover if (!showingFrontCover) { title_y = 436.f; } if (CFG.gui_title_top) { title_y = 24.f + 2.f; // 24 = overscan } if (CFG.gui_title_area.w) { if (xpos > 0) { title_x = CFG.gui_title_area.x + CFG.gui_title_area.w/4; } else { title_x = CFG.gui_title_area.x + CFG.gui_title_area.w/2 - (strlen(gameTitle)*(tx_font.tilew))/2; } title_y = CFG.gui_title_area.y; } // clock if (CFG.gui_clock_pos.x >= 0) { Gui_Print_Clock(CFG.gui_clock_pos.x, CFG.gui_clock_pos.y, CFG.gui_text2, -1); do_clock = false; } if (do_clock) { int x = BACKGROUND_WIDTH/2; int y = title_y + tx_font.tileh/2; Gui_Print_Clock(x, y, CFG.gui_text2, 0); } else { Gui_PrintEx(title_x, title_y, &tx_font, font_color, gameTitle); } } /** * resets the floating cover postions */ void resetFloatingCover() { //reset the floating cover vars float_xrot = 0; float_yrot = 0; float_zrot = 0; } /** * Calculates next position for floating covers */ void calculate_floating_cover() { //do the floating cover thing if the theme wants it or we're showing the back cover if (CFG_cf_theme[CFG_cf_global.theme].floating_cover || !showingFrontCover) { //calculate xrot for float if (float_xrot_up && float_xrot >= float_max_xrot) { float_xrot -= float_speed_increment; float_xrot_up = false; } else if (float_xrot_up) { float_xrot += float_speed_increment; } else if (!float_xrot_up && float_xrot <= -float_max_xrot) { float_xrot += float_speed_increment; float_xrot_up = true; } else { float_xrot -= float_speed_increment; } //calculate yrot for float if (float_yrot_up && float_yrot >= float_max_yrot) { float_yrot -= float_speed_increment; float_yrot_up = false; } else if (float_yrot_up) { float_yrot += float_speed_increment; } else if (!float_yrot_up && float_yrot <= -float_max_yrot) { float_yrot += float_speed_increment; float_yrot_up = true; } else { float_yrot -= float_speed_increment; } //calculate zrot for float if (float_zrot_up && float_zrot >= float_max_zrot) { float_zrot -= float_speed_increment; float_zrot_up = false; } else if (float_zrot_up) { float_zrot += float_speed_increment; } else if (!float_zrot_up && float_zrot <= -float_max_zrot) { float_zrot += float_speed_increment; float_zrot_up = true; } else { float_zrot -= float_speed_increment; } } } /** * Main method used to draw rotated covers. * The basic equation is: * current pos = starting point - ((starting point - end point) * index / number of total frames) * @param *cover Cover object to rotate * @param index int representing the current index in the rotation loop * @param frames int representing the total frame count of the rotation * @param floating if true the cover floats * @param drawReflection if true the cover reflection is drawn, else the cover itself * @param ease int representing the easing level to use: e.g. 0=linear * @return void */ void Coverflow_rotate(struct Cover *cover, int index, int frames, bool floating, bool drawReflection, int ease) { //calculate the new positions cover->currentPos.x = calculateNewPosition(cover->startPos.x, cover->endPos.x, index, frames, ease); cover->currentPos.y = calculateNewPosition(cover->startPos.y, cover->endPos.y, index, frames, ease); cover->currentPos.z = calculateNewPosition(cover->startPos.z, cover->endPos.z, index, frames, ease); cover->currentPos.xrot = calculateNewPosition(cover->startPos.xrot, cover->endPos.xrot, index, frames, ease); cover->currentPos.yrot = calculateNewPosition(cover->startPos.yrot, cover->endPos.yrot, index, frames, ease); cover->currentPos.zrot = calculateNewPosition(cover->startPos.zrot, cover->endPos.zrot, index, frames, ease); cover->currentPos.alpha = calculateNewPosition(cover->startPos.alpha, cover->endPos.alpha, index, frames, ease); cover->currentPos.reflection_bottom = calculateNewColor(cover->startPos.reflection_bottom, cover->endPos.reflection_bottom, index, frames, ease); cover->currentPos.reflection_top = calculateNewColor(cover->startPos.reflection_top, cover->endPos.reflection_top, index, frames, ease); bool favorite = is_favorite(gameList[cover->gi].id); if (floating) { //draw the cover image draw_cover_image(&cover->tx, cover->currentPos.x, cover->currentPos.y, cover->currentPos.z, cover->currentPos.xrot + float_xrot, cover->currentPos.yrot + float_yrot, cover->currentPos.zrot + float_zrot, cover->currentPos.alpha, cover->currentPos.reflection_bottom, cover->currentPos.reflection_top, CFG_cf_global.covers_3d, favorite, cover->selected, drawReflection, cover->gi); } else { //draw the cover image draw_cover_image(&cover->tx, cover->currentPos.x, cover->currentPos.y, cover->currentPos.z, cover->currentPos.xrot, cover->currentPos.yrot, cover->currentPos.zrot, cover->currentPos.alpha, cover->currentPos.reflection_bottom, cover->currentPos.reflection_top, CFG_cf_global.covers_3d, favorite, cover->selected, drawReflection, cover->gi); } } /** * Method that calculates the new frameIndex when switching easing types. This gets called when rotation is stopping. * * @param ease_type the easing type that is being switch to * @param new_framecount int representing the new frame count * @return void */ void calculate_new_easing_frameindex(int ease_type, int new_framecount) { int i = 0; f32 xpos = 0; CFG_cf_global.frameIndex = 1; CFG_cf_global.frameCount = new_framecount; //find the closest matching frame index for the new ease type if (coverCoords_center.startPos.x > coverCoords_center.endPos.x) { for (i=0; i<=CFG_cf_global.frameCount; i++) { xpos = calculateNewPosition(coverCoords_center.startPos.x, coverCoords_center.endPos.x, i, new_framecount, ease_type); if (xpos <= coverCoords_center.currentPos.x) { CFG_cf_global.frameIndex = i; break; } } } else { for (i=0; i= coverCoords_center.currentPos.x) { CFG_cf_global.frameIndex = i; break; } } } } /** * Method that resets the startPos to the currentPos for all right and left covers. * * @return void */ void reset_rotation_startPosition() { int i = 0; //let the side covers keep rotating... if (CFG_cf_global.transition==CF_TRANS_ROTATE_RIGHT) { coverCoords_left[0].startPos = coverCoords_left[0].currentPos; for (i=0; i 1) GRRLIB_prepareAAPass(CFG.gui_antialias, j); else GRRLIB_ResetVideo(); //if moving to/from console mode then fade the backgrounds if (CFG_cf_global.transition == CF_TRANS_MOVE_TO_CONSOLE || CFG_cf_global.transition == CF_TRANS_MOVE_FROM_CONSOLE) { alpha = 255 * CFG_cf_global.frameIndex / CFG_cf_global.frameCount; Gui_set_camera(NULL, 0); if (CFG_cf_global.transition == CF_TRANS_MOVE_TO_CONSOLE) { GRRLIB_DrawImg(0, 0, &tx_bg, 0, 1, 1, 0xFFFFFF00 | (255-alpha)); GRRLIB_DrawImg(0, 0, &tx_bg_con, 0, 1, 1, 0xFFFFFF00 | (alpha)); } else { GRRLIB_DrawImg(0, 0, &tx_bg_con, 0, 1, 1, 0xFFFFFF00 | (255-alpha)); GRRLIB_DrawImg(0, 0, &tx_bg, 0, 1, 1, 0xFFFFFF00 | (alpha)); } Gui_set_camera(NULL, 1); } else { Gui_draw_background(); } // reflections Coverflow_rotate(&coverCoords_center, CFG_cf_global.frameIndex, CFG_cf_global.frameCount, false, true, ease); for (i=0; i=0; i--) { Coverflow_rotate(&coverCoords_left[i], CFG_cf_global.frameIndex, CFG_cf_global.frameCount, false, false, ease); Coverflow_rotate(&coverCoords_right[i], CFG_cf_global.frameIndex, CFG_cf_global.frameCount, false, false, ease); } fadeBackground(); //center cover if (!showingFrontCover || CFG_cf_theme[CFG_cf_global.theme].floating_cover) //float the cover Coverflow_rotate(&coverCoords_center, CFG_cf_global.frameIndex, CFG_cf_global.frameCount, true, false, ease); else Coverflow_rotate(&coverCoords_center, CFG_cf_global.frameIndex, CFG_cf_global.frameCount, false, false, ease); if (CFG.gui_antialias > 1) Gui_RenderAAPass(j); } if (CFG.gui_antialias > 1) { GRRLIB_drawAAScene(CFG.gui_antialias, aa_texBuffer); GRRLIB_ResetVideo(); } if (draw_title) { //if rotating fast then left align title for easier readability if ((CFG_cf_global.frameCount < CFG_cf_theme[CFG_cf_global.theme].rotation_frames) && (CFG_cf_global.transition==CF_TRANS_ROTATE_RIGHT || CFG_cf_global.transition==CF_TRANS_ROTATE_LEFT)) Coverflow_draw_title(selectedCover, 180, ir); else Coverflow_draw_title(selectedCover, -1, ir); } //check if we're done transitioning if (CFG_cf_global.transition > 0) { if (CFG_cf_global.frameIndex >= CFG_cf_global.frameCount) { //rotations should always end at the default (slow) speed if (CFG_cf_global.frameCount < CFG_cf_theme[CFG_cf_global.theme].rotation_frames && (CFG_cf_global.transition==CF_TRANS_ROTATE_RIGHT || CFG_cf_global.transition==CF_TRANS_ROTATE_LEFT)) { Coverflow_init_transition(CFG_cf_global.transition, 0, coverCount, true); } else { //done with this transition so set the cover positions coverCoords_center.currentPos = coverCoords_center.endPos; coverCoords_center.startPos = coverCoords_center.endPos; for (i=0; i < CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers + 1; i++) { coverCoords_left[i].currentPos = coverCoords_left[i].endPos; coverCoords_left[i].startPos = coverCoords_left[i].endPos; coverCoords_right[i].currentPos = coverCoords_right[i].endPos; coverCoords_right[i].startPos = coverCoords_right[i].endPos; } //reset the transition params CFG_cf_global.frameIndex = 0; CFG_cf_global.frameCount = 0; CFG_cf_global.transition = 0; } } else { //if we're rotating fast but we stopped pressing the dpad (or rotating via wiimote) then // we need to recalculate the frameIndex so the easing switchover is smooth if (CFG_cf_global.frameCount < CFG_cf_theme[CFG_cf_global.theme].rotation_frames && (CFG_cf_global.transition==CF_TRANS_ROTATE_RIGHT || CFG_cf_global.transition==CF_TRANS_ROTATE_LEFT)) { if (!rotating_with_wiimote && !Wpad_Held(0) && CFG_cf_global.frameIndex < CFG_cf_global.frameCount * .75) { calculate_new_easing_frameindex(EASING_TYPE_SLOW, CFG_cf_theme[CFG_cf_global.theme].rotation_frames); } } //not done so increase the frame index CFG_cf_global.frameIndex++; } rotating_with_wiimote = 0; } if (CFG.debug == 3) { GRRLIB_Printf(50, 10, &tx_font, CFG.gui_text.color, 1, "center start.x:%f end.x:%f", coverCoords_center.startPos.x, coverCoords_center.endPos.x); GRRLIB_Printf(50, 25, &tx_font, CFG.gui_text.color, 1, "center start.y:%f end.y:%f", coverCoords_center.startPos.y, coverCoords_center.endPos.y); GRRLIB_Printf(50, 40, &tx_font, CFG.gui_text.color, 1, "center start.z:%f end.z:%f", coverCoords_center.startPos.z, coverCoords_center.endPos.z); GRRLIB_Printf(50, 55, &tx_font, CFG.gui_text.color, 1, "center start.yrot:%f end.yrot:%f", coverCoords_center.startPos.yrot, coverCoords_center.endPos.yrot); GRRLIB_Printf(50, 70, &tx_font, CFG.gui_text.color, 1, "trans? %i, framecount: %i, frameindex: %i ease: %i", CFG_cf_global.transition, CFG_cf_global.frameCount, CFG_cf_global.frameIndex, ease); //to see the mouseover screenshot image: //GRRLIB_DrawImg_format(0, 0, tx_screenshot, GX_TF_I8, 0, 1, 1, 0xFFFFFFFF); //currently selected color and cover index: GRRLIB_Printf(200, 410, &tx_font, CFG.gui_text.color, 1.0, "cover(gi): %i color: %X", selectedCover, selectedColor); //mouse pointer position: //GRRLIB_Printf(50, 430, &tx_font, CFG.gui_text.color, 1.0, "sx: %.2f sy: %.2f angle: %.2f v: %d %d %d", ir->sx, ir->sy, ir->angle, ir->raw_valid, ir->smooth_valid, ir->valid); orient_t o; WPAD_Orientation(0, &o); GRRLIB_Printf(50, 450, &tx_font, CFG.gui_text.color, 1.0, "yaw:%.2f pitch: %.2f roll: %.2f ", o.yaw, o.pitch, o.roll); } return selectedCover; } /** * Method that populates a CoverPos (cover position) struct based on the passed in position type. * * @param type int representing the cover position type to use * @param *coverPos the CoverPos to populate * @return void */ void build_coverPos_type(int type, CoverPos *coverPos) { f32 x, y; switch(type){ //position for when viewing the back cover case COVERPOS_FLIP_TO_BACK: coverPos->xrot = 0; coverPos->yrot = 180; coverPos->zrot = 0; coverPos->x = CFG_cf_global.cover_back_xpos; coverPos->y = CFG_cf_global.cover_back_ypos; coverPos->z = CFG_cf_global.cover_back_zpos; coverPos->reflection_bottom = CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom & 0xFFFFFF00; coverPos->reflection_top = CFG_cf_theme[CFG_cf_global.theme].reflections_color_top & 0xFFFFFF00; coverPos->alpha = 255; break; //position of the center cover based on the current theme case COVERPOS_CENTER_THEME: coverPos->xrot = coverCoords_center.themePos.xrot; coverPos->yrot = coverCoords_center.themePos.yrot; coverPos->zrot = coverCoords_center.themePos.zrot; coverPos->x = coverCoords_center.themePos.x; coverPos->y = coverCoords_center.themePos.y; coverPos->z = coverCoords_center.themePos.z; coverPos->reflection_bottom = coverCoords_center.themePos.reflection_bottom; coverPos->reflection_top = coverCoords_center.themePos.reflection_top; coverPos->alpha = coverCoords_center.themePos.alpha; break; //position of the console image (2D cover) case COVERPOS_CONSOLE_2D: //calculate the 3d x and y position of the console cover convert_2dCoords_into_3dCoords(COVER_XCOORD + 80, COVER_YCOORD + 112, -73, &x, &y); coverPos->xrot = 0; coverPos->yrot = 0; coverPos->zrot = 0; coverPos->x = x; coverPos->y = y; coverPos->z = -73; coverPos->reflection_bottom = 0x00000000; coverPos->reflection_top = 0x00000000; coverPos->alpha = 255; break; //position of the console image (fake 3D cover) case COVERPOS_CONSOLE_3D: //calculate the 3d x and y position of the console cover convert_2dCoords_into_3dCoords(COVER_XCOORD + 80, COVER_YCOORD + 112, -80, &x, &y); coverPos->xrot = 0; coverPos->yrot = 33; coverPos->zrot = 0; coverPos->x = x; coverPos->y = y; coverPos->z = -82; coverPos->reflection_bottom = 0x00000000; coverPos->reflection_top = 0x00000000; coverPos->alpha = 255; break; //position of the game loading screen cover case COVERPOS_GAME_LOAD: coverPos->xrot = 0; coverPos->yrot = 0; //33; coverPos->zrot = 0; coverPos->x = 0; coverPos->y = 0; coverPos->z = -50; //-73; coverPos->alpha = 255; coverPos->reflection_bottom = 0x00000000; coverPos->reflection_top = 0x00000000; break; } } /** * Method that draws the center cover for the game options screen * * @param game_sel int representing the index of the selected game to draw * @param x int X position of the cover * @param y int Y position of the cover * @param z int Z position of the cover * @param xrot f32 the X-axis rotation of the cover * @param yrot f32 the Y-axis rotation of the cover * @param zrot f32 the Z-axis rotation of the cover * @return void */ void Coverflow_drawCoverForGameOptions(int game_sel, float x, float y, float z, f32 xrot, f32 yrot, f32 zrot, int cstyle) { Cover cover; bool favorite; int aa, j; GRRLIB_texImg bg_tx; long long t1, t11, t12, t2; if (!grx_cover_init) Coverflow_Grx_Init(); t1 = gettime(); // reset cover indexing to the selected cover setCoverIndexing(gameCnt, game_sel); cache_request_before_and_after(game_sel, 5, 1); // update the cover images from the cache //Coverflow_update_state(); update_cover_state2(&coverCoords_center, cstyle); favorite = is_favorite(gameList[coverCoords_center.gi].id); // init the positioning build_coverPos_type(COVERPOS_GAME_LOAD, &cover.currentPos); // scale the passed in x and y coords to 3d space convert_2dCoords_into_3dCoords(x+80, y+112, -40, &cover.currentPos.x, &cover.currentPos.y); t11 = gettime(); //GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); //GX_SetViewport(0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1); //GX_InvVtxCache(); //GX_InvalidateTexAll(); // capture the background for aa bg_tx = GRRLIB_AAScreen2Texture(); GRRLIB_AAScreen2Texture_buf(&bg_tx, GX_FALSE); t12 = gettime(); aa = (CFG.gui_antialias < 1) ? 1 : CFG.gui_antialias; for(j=0; j < aa; j++) { GRRLIB_prepareAAPass(aa, j); Gui_set_camera(NULL, 0); if (j) Gui_DrawImgFullScreen(&bg_tx, 0xFFFFFFFF, false); Gui_set_camera(NULL, 1); // debug bench if (coverflow_test_grid) { int mx=8, my=4; int nx, ny; for (ny = 0; ny < my; ny++) { for (nx = 0; nx < mx; nx++) { if (ny == my-1 && nx < 2) continue; float x, y, z; float px, py; //, pz; x = (0.5+nx + 0.1*ny) * 640 / mx; y = (0.5+ny) * 480 / my; z = -150; convert_2dCoords_into_3dCoords(x, y, z, &px, &py); draw_cover_image(&coverCoords_center.tx, px, py, z, //cover.currentPos.xrot, yrot, cover.currentPos.zrot, xrot, yrot, zrot, cover.currentPos.alpha, cover.currentPos.reflection_bottom, cover.currentPos.reflection_top, true, favorite, true, false, coverCoords_center.gi); } } } //draw the cover image draw_cover_image(&coverCoords_center.tx, cover.currentPos.x, cover.currentPos.y, cover.currentPos.z + z, //cover.currentPos.xrot, yrot, cover.currentPos.zrot, xrot, yrot, zrot, cover.currentPos.alpha, cover.currentPos.reflection_bottom, cover.currentPos.reflection_top, true, favorite, true, false, coverCoords_center.gi); Gui_RenderAAPass(j); } GRRLIB_drawAAScene(aa, aa_texBuffer); GRRLIB_ResetVideo(); SAFE_FREE(bg_tx.data); t2 = gettime(); if (CFG.debug == 3) { GRRLIB_Printf(20, 60, &tx_font, 0xFF00FFFF, 1, "ms:%6.2f %6.2f %6.2f %6.2f", (float)diff_usec(t1,t2)/1000.0, (float)diff_usec(t1,t11)/1000.0, (float)diff_usec(t11,t12)/1000.0, (float)diff_usec(t12,t2)/1000.0); } } /** * Method used to inititate a new coverflow transition (rotate right/left, spin, etc). * * @param trans_type int representing the transition type to initiate (rotate right/left, spin, etc) * @param speed int representing the transition speed. Set to 0 for the "default" slow speed. * @param coverCount total number of games * @param speed_rampup bool representing if each iteration of the transition should increase in speed * @return int representing the index of the currently selected cover */ int Coverflow_init_transition(int trans_type, int speed, int coverCount, bool speed_rampup) { int numSideCovers, covertype, idx; int i=0; ir_t ir; int slow_rotation_speed = 20; //set the framecount for the transition if (trans_type == CF_TRANS_ROTATE_RIGHT || trans_type == CF_TRANS_ROTATE_LEFT) { //are we already performing this action? if (CFG_cf_global.transition == trans_type && speed > 0) { //check if we're allowed to perform the transition yet if (CFG_cf_global.frameIndex < rotation_start_index) { return -1; } else { if (speed_rampup) { CFG_cf_global.frameCount = CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast; if (rotation_start_index > CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast) rotation_start_index = CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast; else rotation_start_index = 7; //final rotation start - increase to slow it down } else { rotation_start_index = (int)round(calculateNewPosition(slow_rotation_speed, CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast, speed, 100, EASING_TYPE_LINEAR)); CFG_cf_global.frameCount = (int)round(calculateNewPosition(slow_rotation_speed, CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast, speed, 100, EASING_TYPE_LINEAR)); } CFG_cf_global.frameIndex = 1; } } else { //new transition - reset the rotation vars if (speed_rampup) { //first iteration, start at the default (slow) speed. We'll ramp up from here next time. rotation_start_index = 20; //determines when fast rotation starts when holding down the dpad CFG_cf_global.frameCount = CFG_cf_theme[CFG_cf_global.theme].rotation_frames; CFG_cf_global.frameIndex = 1; } else { //calculate framerate based on passed in speed level rotation_start_index = (int)round(calculateNewPosition(slow_rotation_speed, CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast, speed, 100, EASING_TYPE_LINEAR)); idx = (int)round(calculateNewPosition(slow_rotation_speed, CFG_cf_theme[CFG_cf_global.theme].rotation_frames_fast, speed, 100, EASING_TYPE_LINEAR)); if (idx == CFG_cf_theme[CFG_cf_global.theme].rotation_frames) { //rotating from slow to fast so find our new position for linear easing calculate_new_easing_frameindex(EASING_TYPE_LINEAR, idx); } else { CFG_cf_global.frameCount = idx; CFG_cf_global.frameIndex = 1; } } } } //store the number of side covers numSideCovers = CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers; //set the cover start and end positions for the transition switch(trans_type){ case CF_TRANS_ROTATE_RIGHT: //move the img index to the right setCoverIndexing(coverCount, coverCoords_right[0].gi); if (numSideCovers > 0) { //right[0] to center coverCoords_center.startPos = coverCoords_right[0].currentPos; //center to left[0] coverCoords_left[0].startPos = coverCoords_center.currentPos; //side covers for (i=0; i 0) { //left[0] to center coverCoords_center.startPos = coverCoords_left[0].currentPos; //center to right[0] coverCoords_right[0].startPos = coverCoords_center.currentPos; //side covers for (i=0; isy >= 0 && ir->sy <= BACKGROUND_HEIGHT) && (ir->sx >= -160 && ir->sx <= BACKGROUND_WIDTH+160)) { //get rotation data int ir_rot = (int)ir->angle; if (ir_rot < 0) ir_rot += 360; //flip the cover over if they're rotating the wiimote if (ir_rot > 80 && ir_rot < 280){ selected = Coverflow_flip_cover_to_back(true, 1); goto out; } else { selected = Coverflow_flip_cover_to_back(false, 1); } // jump out if pointer scroll disabled if (!CFG.gui_pointer_scroll) goto out; if (CFG.gui_cover_area.h) { if (ir->sy < CFG.gui_cover_area.y || ir->sy > CFG.gui_cover_area.y + CFG.gui_cover_area.h) { goto out; } } //scroll left or right if (ir->sx >= -80 && ir->sx < WIIMOTE_SIDE_SCROLL_WIDTH - 1) { //LEFT if (ir->sx > 20 && ir->sx < WIIMOTE_SIDE_SCROLL_WIDTH - 1) { //speed = (100 / (WIIMOTE_SIDE_SCROLL_WIDTH - 20)) * (WIIMOTE_SIDE_SCROLL_WIDTH - ir->sx); speed = (int)round(1.25 * (f32)(WIIMOTE_SIDE_SCROLL_WIDTH - ir->sx)); } else if (ir->sx <= 20 && ir->sx >= -80) { //max speed speed = 100; } if (speed < 0) speed = 0; rotating_with_wiimote = 1; ret = Coverflow_init_transition(CF_TRANS_ROTATE_LEFT, speed, coverCount, false); if (ret > 0) { cache_release_all(); cache_request_before_and_after(ret, 5, 1); } } else if ((ir->sx > BACKGROUND_WIDTH - WIIMOTE_SIDE_SCROLL_WIDTH + 1) && (ir->sx <= BACKGROUND_WIDTH + 80)) { //RIGHT if ((ir->sx > BACKGROUND_WIDTH - WIIMOTE_SIDE_SCROLL_WIDTH + 1) && (ir->sx < BACKGROUND_WIDTH - 20)) { speed = (int)round(1.25 * (f32)(ir->sx - (BACKGROUND_WIDTH - WIIMOTE_SIDE_SCROLL_WIDTH))); } else if ((ir->sx <= BACKGROUND_WIDTH + 80) && (ir->sx >= BACKGROUND_WIDTH - 20)) { //max speed speed = 100; } if (speed < 0) speed = 0; rotating_with_wiimote = 1; ret = Coverflow_init_transition(CF_TRANS_ROTATE_RIGHT, speed, coverCount, false); if (ret > 0) { cache_release_all(); cache_request_before_and_after(ret, 5, 1); } } } out:; return selected; } /** * Initializes the cover coordinates based on the currently selected theme * @param coverCount total number of games * @param selectedCoverIndex index of the currently selected cover * @param themeChange boolean to determine if a coverflow gui theme change is being performed * @return int representing the index of the currently selected cover */ int Coverflow_initCoverObjects(int coverCount, int selectedCoverIndex, bool themeChange) { int selectedCover, i, numSideCovers; //set the global number of covers CFG_cf_global.number_of_covers = coverCount; if (!themeChange) { memset(coverCoords_left, 0, sizeof(coverCoords_left)); memset(coverCoords_right, 0, sizeof(coverCoords_right)); memset(&coverCoords_center, 0, sizeof(coverCoords_center)); } //if they tried to get crazy with the number of side covers then max them out if (CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers > MAX_COVERFLOW_COVERS) { CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers = MAX_COVERFLOW_COVERS; } numSideCovers = CFG_cf_theme[CFG_cf_global.theme].number_of_side_covers; //center positioning coverCoords_center.themePos.x = CFG_cf_theme[CFG_cf_global.theme].cover_center_xpos; coverCoords_center.themePos.y = CFG_cf_theme[CFG_cf_global.theme].cover_center_ypos; coverCoords_center.themePos.z = CFG_cf_theme[CFG_cf_global.theme].cover_center_zpos; coverCoords_center.themePos.xrot = CFG_cf_theme[CFG_cf_global.theme].cover_center_xrot; coverCoords_center.themePos.yrot = CFG_cf_theme[CFG_cf_global.theme].cover_center_yrot; coverCoords_center.themePos.zrot = CFG_cf_theme[CFG_cf_global.theme].cover_center_zrot; coverCoords_center.themePos.alpha = 255; coverCoords_center.themePos.reflection_bottom = CFG_cf_theme[CFG_cf_global.theme].reflections_color_bottom; coverCoords_center.themePos.reflection_top = CFG_cf_theme[CFG_cf_global.theme].reflections_color_top; if (!themeChange) { coverCoords_center.currentPos = coverCoords_center.themePos; coverCoords_center.startPos = coverCoords_center.themePos; } else { coverCoords_center.startPos = coverCoords_center.currentPos; } coverCoords_center.endPos = coverCoords_center.themePos; //side covers for (i=0; i < numSideCovers; i++) { setCoverPosition_Left(&coverCoords_left[i].themePos, i); if (!themeChange) { coverCoords_left[i].currentPos = coverCoords_left[i].themePos; coverCoords_left[i].startPos = coverCoords_left[i].themePos; } else { coverCoords_left[i].startPos = coverCoords_left[i].currentPos; } coverCoords_left[i].endPos = coverCoords_left[i].themePos; coverCoords_left[i].selected = false; coverCoords_left[i].gi = 0; setCoverPosition_Right(&coverCoords_right[i].themePos, i); if (!themeChange) { coverCoords_right[i].currentPos = coverCoords_right[i].themePos; coverCoords_right[i].startPos = coverCoords_right[i].themePos; } else { coverCoords_right[i].startPos = coverCoords_right[i].currentPos; } coverCoords_right[i].endPos = coverCoords_right[i].themePos; coverCoords_right[i].selected = false; coverCoords_right[i].gi = 0; } //hide the far right and left covers - only shown when rotating setCoverPosition_Right(&coverCoords_right[numSideCovers].themePos, i); coverCoords_right[numSideCovers].hidden = 1; coverCoords_right[numSideCovers].themePos.alpha = 0; coverCoords_right[numSideCovers].themePos.reflection_bottom = coverCoords_right[numSideCovers].themePos.reflection_bottom & 0xFFFFFF00; coverCoords_right[numSideCovers].themePos.reflection_top = coverCoords_right[numSideCovers].themePos.reflection_top & 0xFFFFFF00; coverCoords_right[numSideCovers].currentPos = coverCoords_right[numSideCovers].themePos; coverCoords_right[numSideCovers].startPos = coverCoords_right[numSideCovers].themePos; coverCoords_right[numSideCovers].endPos = coverCoords_right[numSideCovers].themePos; setCoverPosition_Left(&coverCoords_left[numSideCovers].themePos, i); coverCoords_left[numSideCovers].hidden = 1; coverCoords_left[numSideCovers].themePos.alpha = 0; coverCoords_left[numSideCovers].themePos.reflection_bottom = coverCoords_left[numSideCovers].themePos.reflection_bottom & 0xFFFFFF00; coverCoords_left[numSideCovers].themePos.reflection_top = coverCoords_left[numSideCovers].themePos.reflection_top & 0xFFFFFF00; coverCoords_left[numSideCovers].currentPos = coverCoords_left[numSideCovers].themePos; coverCoords_left[numSideCovers].startPos = coverCoords_left[numSideCovers].themePos; coverCoords_left[numSideCovers].endPos = coverCoords_left[numSideCovers].themePos; //init the cover indexing if (!themeChange) //use the passed in cover index when coming from console or grid selectedCover = setCoverIndexing(coverCount, selectedCoverIndex); else //use the current center cover index if changing coverflow themes selectedCover = setCoverIndexing(coverCount, coverCoords_center.gi); //screenshot the new cover positions for the mouseover detection set_cover_stencil_colors(); capture_cover_positions(); //reset the floating cover vars resetFloatingCover(); showingFrontCover = true; background_fade_status = BACKGROUND_FADE_NONE; cover_init = 1; return selectedCover; }