diff --git a/Source/Core/DolphinWX/MemcardManager.cpp b/Source/Core/DolphinWX/MemcardManager.cpp index d181e1da07..f5da01a43a 100644 --- a/Source/Core/DolphinWX/MemcardManager.cpp +++ b/Source/Core/DolphinWX/MemcardManager.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -34,37 +33,24 @@ #define FIRSTPAGE 0 #define ARROWS slot ? "" : ARROW[slot], slot ? ARROW[slot] : "" -static wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, u32 width, u32 height) +static wxImage wxImageFromMemoryRGBA(const u32* data, u32 width, u32 height) { - static const std::array header = { - {0x42, 0x4D, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, - 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // Width - 0x20, 0x00, 0x00, 0x00, // Height - 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, // Data size - 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}}; - - u32 stride = (4 * width); - - u32 bytes = (stride * height) + header.size(); - bytes = (bytes + 3) & ~3; - - u32 data_length = bytes - header.size(); - - std::vector pdata(bytes); - std::copy(header.begin(), header.end(), pdata.begin()); - - u8* const pixelData = &pdata[header.size()]; - - for (u32 y = 0; y < height; y++) - std::memcpy(&pixelData[y * stride], &data[(height - y - 1) * stride], stride); - - std::memcpy(&pdata[18], &width, sizeof(u32)); - std::memcpy(&pdata[22], &height, sizeof(u32)); - std::memcpy(&pdata[34], &data_length, sizeof(u32)); - - wxMemoryInputStream is(pdata.data(), bytes); - return wxBitmap(wxImage(is, wxBITMAP_TYPE_BMP)); + wxImage image(width, height, false); + image.InitAlpha(); + u8* rgb = image.GetData(); + u8* alpha = image.GetAlpha(); + for (u32 y = 0; y < height; ++y) + { + for (u32 x = 0; x < width; ++x) + { + u32 pixel = data[y * width + x]; + *rgb++ = (pixel & 0x00FF0000) >> 16; // Red + *rgb++ = (pixel & 0x0000FF00) >> 8; // Green + *rgb++ = (pixel & 0x000000FF) >> 0; // Blue + *alpha++ = (pixel & 0xFF000000) >> 24; + } + } + return image; } BEGIN_EVENT_TABLE(CMemcardManager, wxDialog) @@ -94,7 +80,8 @@ END_EVENT_TABLE() CMemcardManager::CMemcardManager(wxWindow* parent) : wxDialog(parent, wxID_ANY, _("Memory Card Manager"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER | - wxMAXIMIZE_BOX) + wxMAXIMIZE_BOX), + m_image_list_size(FromDIP(wxSize(96, 32))) { memoryCard[SLOT_A] = nullptr; memoryCard[SLOT_B] = nullptr; @@ -179,6 +166,7 @@ bool CMemcardManager::SaveSettings() void CMemcardManager::CreateGUIControls() { // Create the controls for both memcards + const int space5 = FromDIP(5); const char* ARROW[2] = {"<-", "->"}; @@ -203,11 +191,11 @@ void CMemcardManager::CreateGUIControls() t_Status[slot] = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxEmptyString); - wxBoxSizer* const sPages = new wxBoxSizer(wxHORIZONTAL); - sPages->Add(m_PrevPage[slot], 0, wxEXPAND | wxALL, 1); - sPages->Add(t_Status[slot], 0, wxEXPAND | wxALL, 5); - sPages->Add(0, 0, 1, wxEXPAND | wxALL, 0); - sPages->Add(m_NextPage[slot], 0, wxEXPAND | wxALL, 1); + wxFlexGridSizer* const paging_sizer = new wxFlexGridSizer(3, wxSize(space5, space5)); + paging_sizer->AddGrowableCol(1); + paging_sizer->Add(m_PrevPage[slot], 0, wxEXPAND); + paging_sizer->Add(t_Status[slot], 0, wxALIGN_CENTER); + paging_sizer->Add(m_NextPage[slot], 0, wxEXPAND); m_MemcardPath[slot] = new wxFilePickerCtrl( this, ID_MEMCARDPATH_A + slot, StrToWxStr(File::GetUserPath(D_GCUSER_IDX)), @@ -216,41 +204,51 @@ void CMemcardManager::CreateGUIControls() wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN); m_MemcardList[slot] = new CMemcardListCtrl( - this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, wxSize(350, 400), + this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, FromDIP(wxSize(350, 400)), wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL, mcmSettings); - m_MemcardList[slot]->AssignImageList(new wxImageList(96, 32), wxIMAGE_LIST_SMALL); + m_MemcardList[slot]->AssignImageList( + new wxImageList(m_image_list_size.GetWidth(), m_image_list_size.GetHeight()), + wxIMAGE_LIST_SMALL); sMemcard[slot] = new wxStaticBoxSizer(wxVERTICAL, this, _("Memory Card") + wxString::Format(" %c", 'A' + slot)); - sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxALL, 5); - sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxALL, 5); - sMemcard[slot]->Add(sPages, 0, wxEXPAND | wxALL, 1); + sMemcard[slot]->AddSpacer(space5); + sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxLEFT | wxRIGHT, space5); + sMemcard[slot]->AddSpacer(space5); + sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxLEFT | wxRIGHT, space5); + sMemcard[slot]->AddSpacer(space5); + sMemcard[slot]->Add(paging_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5); + sMemcard[slot]->AddSpacer(space5); } wxBoxSizer* const sButtons = new wxBoxSizer(wxVERTICAL); sButtons->AddStretchSpacer(2); - sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND, 5); - sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND, 5); - sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND, 5); - sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND, 5); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND, 5); - sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND, 5); + sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND); + sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND); sButtons->AddStretchSpacer(); - sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND, 5); + sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND); + sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND); + sButtons->AddStretchSpacer(); + sButtons->Add(m_ConvertToGci, 0, wxEXPAND); + sButtons->AddStretchSpacer(); + sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND); + sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND); + sButtons->AddStretchSpacer(); + sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND); + sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND); + sButtons->AddStretchSpacer(); + sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND); sButtons->AddStretchSpacer(); wxBoxSizer* const sMain = new wxBoxSizer(wxHORIZONTAL); - sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxALL, 5); - sMain->Add(sButtons, 0, wxEXPAND, 0); - sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxALL, 5); + sMain->AddSpacer(space5); + sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxTOP | wxBOTTOM, space5); + sMain->AddSpacer(space5); + sMain->Add(sButtons, 0, wxEXPAND | wxTOP | wxBOTTOM, space5); + sMain->AddSpacer(space5); + sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxTOP | wxBOTTOM, space5); + sMain->AddSpacer(space5); SetSizerAndFit(sMain); Center(); @@ -653,57 +651,73 @@ bool CMemcardManager::ReloadMemcard(const std::string& fileName, int card) u8 nFiles = memoryCard[card]->GetNumFiles(); std::vector images(nFiles * 2); + static constexpr unsigned int BANNER_WIDTH = 96; + static constexpr unsigned int ANIM_FRAME_WIDTH = 32; + static constexpr unsigned int IMAGE_HEIGHT = 32; + static constexpr unsigned int ANIM_MAX_FRAMES = 8; + + std::vector pxdata(BANNER_WIDTH * IMAGE_HEIGHT); + std::vector anim_delay(ANIM_MAX_FRAMES); + std::vector anim_data(ANIM_FRAME_WIDTH * IMAGE_HEIGHT * ANIM_MAX_FRAMES); for (u8 i = 0; i < nFiles; i++) { - static u32 pxdata[96 * 32]; - static u8 animDelay[8]; - static u32 animData[32 * 32 * 8]; + u8 file_index = memoryCard[card]->GetFileIndex(i); + u32 num_frames = + memoryCard[card]->ReadAnimRGBA8(file_index, anim_data.data(), anim_delay.data()); - u8 fileIndex = memoryCard[card]->GetFileIndex(i); - int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay); - - if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata)) + // Decode Save File Animation + wxImage anim_img_strip; + if (num_frames > 0) { - memset(pxdata, 0, 96 * 32 * 4); + unsigned int frames = BANNER_WIDTH / ANIM_FRAME_WIDTH; - if (numFrames > 0) // Just use the first one + if (num_frames < frames) { - u32* icdata = animData; + frames = num_frames; - for (int y = 0; y < 32; y++) + // Clear unused frame's pixels from the buffer. + std::fill(pxdata.begin(), pxdata.end(), 0); + } + + for (unsigned int f = 0; f < frames; ++f) + { + for (unsigned int y = 0; y < IMAGE_HEIGHT; ++y) { - for (int x = 0; x < 32; x++) + for (unsigned int x = 0; x < ANIM_FRAME_WIDTH; ++x) { - pxdata[y * 96 + x + 32] = icdata[y * 32 + x]; // | 0xFF000000 + // NOTE: pxdata is stacked horizontal, anim_data is stacked vertical + pxdata[y * BANNER_WIDTH + f * ANIM_FRAME_WIDTH + x] = + anim_data[f * ANIM_FRAME_WIDTH * IMAGE_HEIGHT + y * IMAGE_HEIGHT + x]; } } } + anim_img_strip = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT); } - - wxBitmap map = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); - images[i * 2] = list->Add(map); - - if (numFrames > 0) + else { - memset(pxdata, 0, 96 * 32 * 4); - int frames = 3; - - if (numFrames < frames) - frames = numFrames; - - for (int f = 0; f < frames; f++) - { - for (int y = 0; y < 32; y++) - { - for (int x = 0; x < 32; x++) - { - pxdata[y * 96 + x + 32 * f] = animData[f * 32 * 32 + y * 32 + x]; - } - } - } - wxBitmap icon = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32); - images[i * 2 + 1] = list->Add(icon); + // No Animation found, use an empty placeholder instead. + anim_img_strip.Create(BANNER_WIDTH, IMAGE_HEIGHT, false); + anim_img_strip.Clear(0xFF); + anim_img_strip.SetMaskColour(0xFF, 0xFF, 0xFF); } + + // Decode Banner if it exists + { + wxImage image; + if (memoryCard[card]->ReadBannerRGBA8(file_index, pxdata.data())) + { + image = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT); + } + else + { + // Use first frame of animation instead. + image = anim_img_strip.Size(wxSize(ANIM_FRAME_WIDTH, IMAGE_HEIGHT), wxPoint(0, 0)); + } + images[i * 2] = list->Add(WxUtils::ScaleImageToBitmap(image, this, m_image_list_size)); + } + + images[i * 2 + 1] = + list->Add(WxUtils::ScaleImageToBitmap(anim_img_strip, this, m_image_list_size)); } int pagesMax = (mcmSettings.usePages) ? (page[card] + 1) * itemsPerPage : 128; diff --git a/Source/Core/DolphinWX/MemcardManager.h b/Source/Core/DolphinWX/MemcardManager.h index 3f307117b9..edfd5fac74 100644 --- a/Source/Core/DolphinWX/MemcardManager.h +++ b/Source/Core/DolphinWX/MemcardManager.h @@ -131,5 +131,6 @@ private: void OnRightClick(wxMouseEvent& event); }; + wxSize m_image_list_size; CMemcardListCtrl* m_MemcardList[2]; };