diff --git a/Source/Core/Common/Src/ColorUtil.cpp b/Source/Core/Common/Src/ColorUtil.cpp index 52ffec0803..5e5143549a 100644 --- a/Source/Core/Common/Src/ColorUtil.cpp +++ b/Source/Core/Common/Src/ColorUtil.cpp @@ -31,7 +31,7 @@ const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF }; u32 Decode5A3(u16 val) { - const u32 bg_color = 0x00000000; + const u32 bg_color = 0xFFFFFFFF; int r, g, b, a; diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 381f942925..9b72a0313c 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -473,11 +473,20 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const return format; } -u16 GCMemcard::DEntry_AnimSpeed(u8 index) const +std::string GCMemcard::DEntry_AnimSpeed(u8 index) const { if (!m_valid || index > DIRLEN) - return 0xFF; - return BE16(CurrentDir->Dir[index].AnimSpeed); + return ""; + int x = CurrentDir->Dir[index].AnimSpeed[0]; + std::string speed; + for(int i = 0; i < 16; i++) + { + if (i == 8) x = CurrentDir->Dir[index].AnimSpeed[1]; + speed.push_back((x & 0x80) ? '1' : '0'); + x = x << 1; + } + speed.push_back(0); + return speed; } std::string GCMemcard::DEntry_Permissions(u8 index) const @@ -1086,15 +1095,18 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const // To ensure only one type of icon is used // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon - int fmtCheck = 0; + //int fmtCheck = 0; int formats = BE16(CurrentDir->Dir[index].IconFmt); int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); int flags = CurrentDir->Dir[index].BIFlags; - // Timesplitters 2 is the only game that I see this in + // Timesplitters 2 and 3 is the only game that I see this in // May be a hack - if (flags == 0xFB) flags = ~flags; + //if (flags == 0xFB) flags = ~flags; + // Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant. + // Something similar happens with Wario Ware Inc. AnimSpeed + int bnrFormat = (flags&3); u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); @@ -1110,7 +1122,6 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const switch (bnrFormat) { case 1: - case 3: animData += 96*32 + 2*256; // image+palette break; case 2: @@ -1122,40 +1133,48 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const u8* data[8]; int frames = 0; - for (int i = 0; i < 8; i++) { fmts[i] = (formats >> (2*i))&3; - delays[i] = ((fdelays >> (2*i))&3) << 2; + delays[i] = ((fdelays >> (2*i))&3); data[i] = animData; - if (!fmtCheck) fmtCheck = fmts[i]; - if (fmtCheck == fmts[i]) + if (!delays[i]) + { + //First icon_speed = 0 indicates there aren't any more icons + break; + } + //If speed is set there is an icon (it can be a "blank frame") + frames++; + if (fmts[i] != 0) { switch (fmts[i]) { case CI8SHARED: // CI8 with shared palette animData += 32*32; - frames++; break; case RGB5A3: // RGB5A3 animData += 32*32*2; - frames++; break; case CI8: // CI8 with own palette animData += 32*32 + 2*256; - frames++; break; } } } u16* sharedPal = (u16*)(animData); + int j = 0; for (int i = 0; i < 8; i++) { - if (fmtCheck == fmts[i]) + if (!delays[i]) + { + //First icon_speed = 0 indicates there aren't any more icons + break; + } + if (fmts[i] != 0) { switch (fmts[i]) { @@ -1165,6 +1184,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const break; case RGB5A3: // RGB5A3 decode5A3image(buffer, (u16*)(data[i]), 32, 32); + buffer += 32*32; break; case CI8: // CI8 with own palette u16 *paldata = (u16*)(data[i] + 32*32); @@ -1173,6 +1193,33 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const break; } } + else + { + //Speed is set but there's no actual icon + //This is used to reduce animation speed in Pikmin and Luigi's Mansion for example + //These "blank frames" show the next icon + for(j=i; j<8;++j) + { + if (fmts[j] != 0) + { + switch (fmts[j]) + { + case CI8SHARED: // CI8 with shared palette + decodeCI8image(buffer,data[j],sharedPal,32,32); + break; + case RGB5A3: // RGB5A3 + decode5A3image(buffer, (u16*)(data[j]), 32, 32); + buffer += 32*32; + break; + case CI8: // CI8 with own palette + u16 *paldata = (u16*)(data[j] + 32*32); + decodeCI8image(buffer, data[j], paldata, 32, 32); + buffer += 32*32; + break; + } + } + } + } } return frames; @@ -1269,7 +1316,6 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv); } - void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2) { u32 serial[8]; @@ -1349,7 +1395,7 @@ s32 GCMemcard::PSO_MakeSaveGameValid(DEntry& direntry, std::vector &Fi if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0) { // check for PSO3 system file - if (strcmp((char*)&FileBuffer[0].block[0x08],"PSO3_SYSTEM")==0) + if (strcmp((char*)direntry.Filename,"PSO3_SYSTEM")==0) { // PSO3 data block size adjustment pso3offset = 0x10; diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index d2de93effb..557187b384 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -116,8 +116,8 @@ private: // bits 0 and 1: image format // 00 no banner // 01 CI8 banner - // 01 RGB5A3 banner - // 11 ? maybe ==01? haven't seen it + // 10 RGB5A3 banner + // 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner // u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000 @@ -213,7 +213,7 @@ public: u32 DEntry_ModTime(u8 index) const; u32 DEntry_ImageOffset(u8 index) const; std::string DEntry_IconFmt(u8 index) const; - u16 DEntry_AnimSpeed(u8 index) const; + std::string DEntry_AnimSpeed(u8 index) const; std::string DEntry_Permissions(u8 index) const; u8 DEntry_CopyCounter(u8 index) const; // get first block for file diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index bf47a23c53..76c77a0543 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -520,6 +520,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) ? wxString::FromAscii("") : wxString::From8BitData(DefaultIOPath.c_str()), wxEmptyString, wxEmptyString, + _("GameCube Savegame files(*.gci;*.gcs;*.sav)") + wxString(wxT("|*.gci;*.gcs;*.sav|")) + _("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) + _("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) + _("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")),