Changed icon loading code for proper handling of icons that use "blank frames" such as Luigi's Mansion and Pikmin. All icons should be correctly displayed now.

2 methods for showing the icos: time based and frame based (defined in freetype.h)
This commit is contained in:
sulokutdcmago
2012-10-06 09:53:16 +00:00
parent 3c82ef2e0e
commit bc4b511ff1
6 changed files with 237 additions and 172 deletions

View File

@@ -38,7 +38,8 @@ extern card_stat CardStatus;
extern int cancel;
extern int doall;
extern int mode;
extern s32 MEM_CARD;
extern s32 MEM_CARD;
extern u16 bannerdata[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
extern u8 bannerdataCI[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
extern u8 icondata[8][1024] ATTRIBUTE_ALIGN (32);
@@ -46,8 +47,11 @@ extern u16 icondataRGB[8][1024] ATTRIBUTE_ALIGN (32);
extern u16 tlut[9][256] ATTRIBUTE_ALIGN (32);
extern u16 tlutbanner[256] ATTRIBUTE_ALIGN (32);
extern int numicons;
extern int frametable[8];
extern int lastframe;
extern int frametable[2*CARD_MAXICONS - 2];
extern int iconindex[2*CARD_MAXICONS - 2];
extern int lastframe;
extern int lasticon;
extern Header cardheader;
extern s32 memsize, sectsize;
extern syssramex *sramex;
@@ -64,7 +68,8 @@ extern int screenheight;
extern u32 *xfb[2];
extern int whichfb;
extern GXRModeObj *vmode;
extern int vmode_60hz;
extern int vmode_60hz;
extern u32 retraceCount;
/*** File listings ***/
extern card_dir CardList[];
@@ -824,18 +829,6 @@ void showSaveInfo(int sel)
else if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_CI) {
bannerloadCI(bannerdataCI, tlutbanner);
}
//Show first icon
if ((gci.icon_fmt&CARD_ICON_MASK)== 1) {
//CI with shared palette
iconloadCI(icondata[0], tlut[8]);
}
else if ((gci.icon_fmt&CARD_ICON_MASK)== 3) {
iconloadCI(icondata[0], tlut[0]);
}
else if ((gci.icon_fmt&CARD_ICON_MASK)== 2) {
iconloadRGB(icondataRGB[0]);
}
/*** Display relevant info for this save ***/
sprintf(txt, "#%d %s/%s", sel, gamecode, company);
@@ -1100,17 +1093,20 @@ static u8 CalculateFrameRate()
}
return FPS;
}
#endif
int getdurationmilisecs(u16 icon_speed, int index)
{
int speed = ((icon_speed >> (2*index))&CARD_SPEED_MASK)*4;
#endif
#ifdef USE_TIME
int getdurationmilisecs(u16 icon_speed, int index, int bounce)
{
int speed = SDCARD_GetIconSpeedBounce(icon_speed,index,bounce)*4;
if(vmode_60hz){
return 1000/(60/speed);
}else{
return 1000/(50/speed);
}
}
}
#endif
/****************************************************************************
* ShowSelector
@@ -1133,10 +1129,14 @@ int ShowSelector (int saveinfo)
int selection = 0;
//animated icon display vars
int currframe = 0;
int reverse = 0;
int bounceindex;
#ifdef USE_TIME
u64 lasttime, currtime;
lasttime = ticks_to_millisecs(gettime());
currtime = ticks_to_millisecs(gettime());
lasttime = currtime - 250;
#else
int i;
#endif
#ifdef DEBUG_VALUES
u8 fps = 0;
@@ -1146,10 +1146,6 @@ int ShowSelector (int saveinfo)
while (quit == 0)
{
currtime = ticks_to_millisecs(gettime());
#ifdef DEBUG_VALUES
fps = CalculateFrameRate();
#endif
if (redraw)
{
//clear buffers
@@ -1164,59 +1160,66 @@ int ShowSelector (int saveinfo)
//reinit variables
redraw = 0;
reverse = 0;
currframe = 1;
lasttime = ticks_to_millisecs(gettime());
currframe = 0;
bounceindex = CARD_MAXICONS;//This ensures getting correct duration values for non-bouncing animations
if (SDCARD_GetIconAnim(gci.banner_fmt) == CARD_ANIM_BOUNCE)
{
bounceindex = 0;
while(SDCARD_GetIconSpeed(gci.icon_speed, bounceindex) != 0 && bounceindex < CARD_MAXICONS)
{
bounceindex++;
}
}
#ifdef USE_TIME
lasttime -= 250;//to ensure first icon will be loaded
#endif
}
#ifdef DEBUG_VALUES
sprintf (test, "FPS%d numicons%d CF%d LF%d FT%d animtype%d speed%d", fps, numicons, currframe, lastframe, frametable[currframe], CHECK_BIT(gci.banner_fmt,2), ((gci.icon_speed >> (2*currframe))&CARD_SPEED_MASK)*4 );
#ifdef DEBUG_VALUES
fps = CalculateFrameRate();
sprintf (test, "%d FPS%d numicons%02d lasticon%02d CF%02d LF%03d FT%03d II%02d animtype%d speed%02d", retraceCount, fps, numicons, lasticon, currframe, lastframe, frametable[currframe], iconindex[currframe], SDCARD_GetIconAnim(gci.banner_fmt), SDCARD_GetIconSpeedBounce(gci.icon_speed,currframe,bounceindex)*4 );
ShowAction(test);
#endif
if (lastframe)
{
#ifdef USE_TIME
currtime = ticks_to_millisecs(gettime());
if((currtime - lasttime) >= getdurationmilisecs(gci.icon_speed, currframe, bounceindex) )
{
#else
currframe = retraceCount % lastframe;
for (i = 0; i < 2 * CARD_MAXICONS - 2; ++i)
{
if (currframe < frametable[i])
{
break;
}
}
currframe = i;
#endif
//If there's a real icon show it, if not just wait until next icon frame
if ( SDCARD_GetIconFmt(gci.icon_fmt,iconindex[currframe])== 1) {
//CI with shared palette
iconloadCI(icondata[iconindex[currframe]], tlut[8]);
}
else if ( SDCARD_GetIconFmt(gci.icon_fmt,iconindex[currframe])== 3) {
iconloadCI(icondata[iconindex[currframe]], tlut[iconindex[currframe]]);
}
else if ( SDCARD_GetIconFmt(gci.icon_fmt,iconindex[currframe])== 2) {
iconloadRGB(icondataRGB[iconindex[currframe]]);
}
//ShowScreen();
if (numicons > 1){
if((currtime - lasttime) >= getdurationmilisecs(gci.icon_speed, currframe) ){
//If there's a real icon show it, if not just wait until next icon frame
if (frametable[currframe]){
if ( ((gci.icon_fmt >> (2*currframe))&CARD_ICON_MASK)== 1) {
//CI with shared palette
iconloadCI(icondata[currframe], tlut[8]);
}
else if ( ((gci.icon_fmt >> (2*currframe))&CARD_ICON_MASK)== 3) {
iconloadCI(icondata[currframe], tlut[currframe]);
}
else if ( ((gci.icon_fmt >> (2*currframe))&CARD_ICON_MASK)== 2) {
iconloadRGB(icondataRGB[currframe]);
}
ShowScreen();
}
//Each bit pair in gci.icon_speed states for an icon's speed.
//Blank bit pairs can be used to delay the animation
//Check animation type (ping pong style if true)
if (CHECK_BIT(gci.banner_fmt,2)){
if (reverse) currframe --;
if (!reverse) currframe ++;
//Bounce back
if (currframe > lastframe){
reverse = 1;
currframe = lastframe -1;
}else if (currframe < 0){
reverse = 0;
currframe = 1;
}
}else{
currframe ++;
if (currframe > lastframe){
currframe = 0;
}
}
lasttime = currtime;
}
}
currframe ++;
if (currframe > lasticon)
{
currframe = 0;
}
#ifdef USE_TIME
lasttime = currtime;
}
#endif
}
p = PAD_ButtonsDown (0);
#ifdef HW_RVL

View File

@@ -12,11 +12,12 @@
#define RESTORE_MODE 400
//#define RELOAD_MODE 500 /* Free mode */
//pos 0 is less significant bit and pos 7 the most significant
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
//Uncomment this definiton to show some debug values on screen
//#define DEBUG_VALUES
//#define DEBUG_VALUES
//Uncomment this definiton to use time lapse for icon duration instead of retrace count
//Time code is mantained as an alternative example of animating the icons
#define USE_TIME
#ifdef HW_RVL
void initialise_power() ;

View File

@@ -18,6 +18,7 @@
#define SDCARD_GetBannerFmt(banner_fmt) ((banner_fmt) & 0x03)
#define SDCARD_GetIconFmt(icon_fmt,n) (((icon_fmt)>>(2*(n))) & 0x03)
#define SDCARD_GetIconSpeed(icon_speed,n) (((icon_speed)>>(2*(n))) & 0x03)
#define SDCARD_GetIconSpeedBounce(icon_speed,n,i) ((n) < (i) ? (((icon_speed)>>(2*(n))) & 0x03) : (((icon_speed)>>(2*((i*2)-2-n)) & 0x03)) )
#define SDCARD_GetIconAnim(banner_fmt) ((banner_fmt) & 0x04)
typedef struct {

View File

@@ -44,7 +44,8 @@ GXRModeObj *vmode; /*** Graphics Mode Object ***/
u32 *xfb[2] = { NULL, NULL }; /*** Framebuffers ***/
int whichfb = 0; /*** Frame buffer toggle ***/
int screenheight;
int vmode_60hz = 0;
int vmode_60hz = 0;
u32 retraceCount;
extern u8 filelist[1024][1024];
extern bool offsetchanged;
@@ -53,8 +54,9 @@ s32 MEM_CARD = CARD_SLOTB;
extern syssramex *sramex;
extern u8 imageserial[12];
static void updatePAD()
{
static void updatePAD(u32 retrace)
{
retraceCount = retrace;
PAD_ScanPads();
#ifdef HW_RVL
WPAD_ScanPads();

View File

@@ -41,8 +41,10 @@ u16 bannerdata[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
Needs decoding by bannerloadCI function before we can show it ***/
u8 bannerdataCI[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
int numicons;
int frametable[8];
int lastframe;
int frametable[2*CARD_MAXICONS - 2];
int iconindex[2*CARD_MAXICONS - 2];
int lastframe;
int lasticon;
/*** This matrix will serve as our array of filenames for each file on the card
We add 10 to filenamelen since we add on game company info***/
u8 filelist[1024][1024];
@@ -104,7 +106,7 @@ int MountCard(int cslot)
/*** Mount the card ***/
ret = CARD_Mount (cslot, SysArea, card_removed);
if (ret >= 0) break;
VIDEO_WaitVSync ();
tries++;
}
@@ -115,7 +117,7 @@ int MountCard(int cslot)
return isMounted;
}
/*** If this point is reached, something went wrong ***/
return ret;
}
@@ -343,59 +345,86 @@ int CardReadFileHeader (int slot, int id)
offset += 3072;
memcpy(tlutbanner, offset, 512);
offset += 512;
}
//Icon data
check_fmt = gci.icon_fmt;
check_speed = gci.icon_speed;
int shared_pal = 0;
lastframe = 0;
numicons = 0;
for (i=0;i<8;i++){
//this stores if the frame has a real icon or not
//no need to clear all values since we will only use the ones until last frame
frametable[i] = 0;
//Animation speed is mandatory to be set even for a single icon
//When a speed is 0 there are no more icons
//Some games may have bits set after the "blank icon" both in
//speed (Baten Kaitos) and format (Wario Ware Inc.) bytes, which are just garbage
if (!(check_speed&CARD_ICON_MASK)){
break;
}else
{//We've got a frame
lastframe=i;
if (check_fmt & CARD_ICON_MASK){
//count the number of real icons
numicons++;
frametable[i]=1; //There's a real icon
//CI with shared palette
if ((check_fmt&CARD_ICON_MASK) == 1) {
memcpy(icondata[i], offset, 1024);
}
//Icon data
int shared_pal = 0;
lastframe = 0;
numicons = 0;
int j =0;
i=0;
int current_icon = 0;
for (current_icon=0;i<CARD_MAXICONS;++current_icon){
//no need to clear all values since we will only use the ones until lasticon
frametable[current_icon] = 0;
iconindex[current_icon] = 0;
//Animation speed is mandatory to be set even for a single icon
//When a speed is 0 there are no more icons
//Some games may have bits set after the "blank icon" both in
//speed (Baten Kaitos) and format (Wario Ware Inc.) bytes, which are just garbage
if (!SDCARD_GetIconSpeed(gci.icon_speed,current_icon)){
break;
}else
{//We've got a frame
lastframe+=SDCARD_GetIconSpeed(gci.icon_speed,current_icon)*4;//Count the total frames
frametable[current_icon]=lastframe; //Store the end frame of the icon
if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) != 0)
{
//count the number of real icons
numicons++;
iconindex[current_icon]=current_icon; //Map the icon
//CI with shared palette
if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 1) {
memcpy(icondata[current_icon], offset, 1024);
offset += 1024;
shared_pal = 1;
}
//CI with palette after the icon
else if ((check_fmt&CARD_ICON_MASK) == 3)
{
memcpy(icondata[i], offset, 1024);
offset += 1024;
memcpy(tlut[i], offset, 512);
offset += 512;
}
//RGB 16 bit icon
else if ((check_fmt&CARD_ICON_MASK) == 2)
{
memcpy(icondataRGB[i], offset, 2048);
offset += 2048;
}
}
}
check_fmt = check_fmt >> 2;
check_speed = check_speed >> 2;
}
shared_pal = 1;
}
//CI with palette after the icon
else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 3)
{
memcpy(icondata[current_icon], offset, 1024);
offset += 1024;
memcpy(tlut[current_icon], offset, 512);
offset += 512;
}
//RGB 16 bit icon
else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 2)
{
memcpy(icondataRGB[current_icon], offset, 2048);
offset += 2048;
}
}else
{ //Get next real icon
for(j=current_icon;j<CARD_MAXICONS;++j){
if (SDCARD_GetIconFmt(gci.icon_fmt,j) != 0)
{
iconindex[current_icon]=j; //Map blank frame to next real icon
break;
}
}
}
}
}
lasticon = current_icon-1;
//Now get icon indexes for ping-pong style icons
if (SDCARD_GetIconAnim(gci.banner_fmt) == CARD_ANIM_BOUNCE && current_icon>1) //We need at least 3 icons
{
j=current_icon;
for (i = current_icon-2; 0 < i; --i, ++j)
{
lastframe += SDCARD_GetIconSpeed(gci.icon_speed,i)*4;
frametable[j] = lastframe;
iconindex[j] = iconindex[i];
}
lasticon = j-1;
}
//Get the shared palette
if (shared_pal) memcpy(tlut[8], offset, 512);
@@ -558,7 +587,7 @@ int CardWriteFile (int slot)
continue;
}
}
/*** User canceled - abort ***/
CARD_Unmount (slot);
WaitCardError("File already exists", err);
@@ -589,13 +618,13 @@ tryagain:
{
WaitCardError("MCDel", err);
CARD_SetCompany(NULL);
CARD_SetGamecode(NULL);
CARD_SetGamecode(NULL);
CARD_Unmount (slot);
return 0;
}
goto tryagain;
}
}
}
}
//Return To show all so we don't have errors
CARD_SetCompany(NULL);
@@ -631,7 +660,7 @@ tryagain:
/*** Finally, update the status ***/
CARD_SetStatus (slot, CardFile.filenum, &CardStatus);
//For some reason this sets the file to Move->allowed, Copy->not allowed, Public file instead of the actual permission value
CARD_SetAttributes(slot, CardFile.filenum, &permission);
CARD_SetAttributes(slot, CardFile.filenum, &permission);
#else
__card_setstatusex(slot, CardFile.filenum, &gci);
#endif
@@ -649,7 +678,7 @@ tryagain:
void WaitCardError(char *src, int error)
{
char msg[1024], err[256];
//Error message possibilites
switch (error)
{
@@ -784,14 +813,14 @@ void MC_FormatMode(s32 slot)
{
int erase = 1;
int err;
//0 = B wass pressed -> ask again
if (!slot){
erase = WaitPromptChoice("Are you sure you want to format memory card in slot A?", "Format", "Cancel");
}else{
erase = WaitPromptChoice("Are you sure you want to format memory card in slot B?", "Format", "Cancel");
}
if (!erase){
if (!slot){
erase = WaitPromptChoiceAZ("All contents of memory card in slot A will be erased!", "Format", "Cancel");
@@ -837,7 +866,7 @@ void MC_FormatMode(s32 slot)
//The following code is made by Ralf at GSCentral forums (gscentral.org)
//http://board.gscentral.org/retro-hacking/53093.htm#post188949
// u8 FileBuffer[MAXFILEBUFFER]: .gci file buffer
// u8 FileBuffer[MAXFILEBUFFER]: .gci file buffer
// MCDATAOFFSET: .gci header size (0x40 bytes)
/*************************************************************/

View File

@@ -29,6 +29,7 @@
extern u8 FileBuffer[MAXFILEBUFFER] ATTRIBUTE_ALIGN (32);
extern Header cardheader;
extern u8 CommentBuffer[64] ATTRIBUTE_ALIGN (32);
extern u16 bannerdata[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
extern u8 bannerdataCI[CARD_BANNER_W*CARD_BANNER_H] ATTRIBUTE_ALIGN (32);
extern u8 icondata[8][1024] ATTRIBUTE_ALIGN (32);
@@ -36,8 +37,11 @@ extern u16 icondataRGB[8][1024] ATTRIBUTE_ALIGN (32);
extern u16 tlut[9][256] ATTRIBUTE_ALIGN (32);
extern u16 tlutbanner[256] ATTRIBUTE_ALIGN (32);
extern int numicons;
extern int frametable[8];
extern int frametable[2*CARD_MAXICONS - 2];
extern int iconindex[2*CARD_MAXICONS - 2];
extern int lastframe;
extern int lasticon;
extern u8 filelist[1024][1024];
extern u32 maxfile;
extern GCI gci;
@@ -254,7 +258,6 @@ int SDLoadMCImageHeader(char *sdfilename)
//int bytesToRead = 0;
long bytesToRead = 0;
int i;
u16 check_fmt, check_speed;
/*** Clear the work buffers ***/
memset (FileBuffer, 0, MAXFILEBUFFER);
@@ -399,62 +402,88 @@ int SDLoadMCImageHeader(char *sdfilename)
fseek(handle, MCDATAOFFSET + OFFSET + gci.icon_addr, SEEK_SET);
/*** Get the Banner/Icon Data from the save file ***/
if ((gci.banner_fmt&CARD_BANNER_MASK) == CARD_BANNER_RGB) {
if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_RGB) {
//RGB banners are 96*32*2 in size
fread (bannerdata, 1, 6144, handle);
}
else if ((gci.banner_fmt&CARD_BANNER_MASK) == CARD_BANNER_CI) {
else if (SDCARD_GetBannerFmt(gci.banner_fmt) == CARD_BANNER_CI) {
fread(bannerdataCI, 1, 3072, handle);
fread(tlutbanner, 1, 512, handle);
}
//Icon data
check_fmt = gci.icon_fmt;
check_speed = gci.icon_speed;
int shared_pal = 0;
lastframe = 0;
numicons = 0;
for (i=0;i<8;i++){
//this stores if the frame has a real icon or not
//no need to clear all values since we will only use the ones until last frame
frametable[i] = 0;
int j =0;
i=0;
int current_icon = 0;
for (current_icon=0;i<CARD_MAXICONS;++current_icon){
//no need to clear all values since we will only use the ones until lasticon
frametable[current_icon] = 0;
iconindex[current_icon] = 0;
//Animation speed is mandatory to be set even for a single icon
//When a speed is 0 there are no more icons
//Some games may have bits set after the "blank icon" both in
//speed (Baten Kaitos) and format (Wario Ware Inc.) bytes, which are just garbage
if (!(check_speed&CARD_ICON_MASK)){
if (!SDCARD_GetIconSpeed(gci.icon_speed,current_icon)){
break;
}else
{//We've got a frame
lastframe=i;
lastframe+=SDCARD_GetIconSpeed(gci.icon_speed,current_icon)*4;//Count the total frames
frametable[current_icon]=lastframe; //Store the end frame of the icon
if (check_fmt & CARD_ICON_MASK){
if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) != 0)
{
//count the number of real icons
numicons++;
frametable[i]=1; //There's a real icon
iconindex[current_icon]=current_icon; //Map the icon
//CI with shared palette
if ((check_fmt&CARD_ICON_MASK) == 1) {
fread(icondata[i], 1, 1024, handle);
if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 1) {
fread(icondata[current_icon], 1, 1024, handle);
shared_pal = 1;
}
//CI with palette after the icon
else if ((check_fmt&CARD_ICON_MASK) == 3)
else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 3)
{
fread(icondata[i], 1, 1024, handle);
fread(tlut[i], 1, 512, handle);
fread(icondata[current_icon], 1, 1024, handle);
fread(tlut[current_icon], 1, 512, handle);
}
//RGB 16 bit icon
else if ((check_fmt&CARD_ICON_MASK) == 2)
else if (SDCARD_GetIconFmt(gci.icon_fmt,current_icon) == 2)
{
fread(icondataRGB[i], 1, 2048, handle);
fread(icondataRGB[current_icon], 1, 2048, handle);
}
}else
{ //Get next real icon
for(j=current_icon;j<CARD_MAXICONS;++j){
if (SDCARD_GetIconFmt(gci.icon_fmt,j) != 0)
{
iconindex[current_icon]=j; //Map blank frame to next real icon
break;
}
}
}
}
check_fmt = check_fmt >> 2;
check_speed = check_speed >> 2;
}
lasticon = current_icon-1;
//Now get icon indexes for ping-pong style icons
if (SDCARD_GetIconAnim(gci.banner_fmt) == CARD_ANIM_BOUNCE && current_icon>1) //We need at least 3 icons
{
j=current_icon;
for (i = current_icon-2; 0 < i; --i, ++j)
{
lastframe += SDCARD_GetIconSpeed(gci.icon_speed,i)*4;
frametable[j] = lastframe;
iconindex[j] = iconindex[i];
}
lasticon = j-1;
}
//Get the shared palette
if (shared_pal) fread(tlut[8], 1, 512, handle);