2323#include " fmt/format.h"
2424#include " gui/widgets/memcard_manager.h"
2525
26+ #define STB_IMAGE_WRITE_IMPLEMENTATION
27+ #include " stb/stb_image_write.h"
28+
2629PCSX ::Widgets::MemcardManager::MemcardManager() {
2730 m_memoryEditor.OptShowDataPreview = true ;
2831 m_memoryEditor.OptUpperCaseHex = false ;
@@ -167,6 +170,12 @@ bool PCSX::Widgets::MemcardManager::draw(const char* title) {
167170 selectedBlock = i;
168171 m_pendingAction.popupText = fmt::format (" Choose block to swap block {} with" , selectedBlock);
169172 }
173+ ImGui::SameLine ();
174+
175+ buttonName = fmt::format (_ (" Export PNG##{}" ), i);
176+ if (ImGui::SmallButton (buttonName.c_str ())) {
177+ exportPNG (i, block);
178+ }
170179 }
171180 ImGui::EndTable ();
172181 }
@@ -212,7 +221,7 @@ bool PCSX::Widgets::MemcardManager::draw(const char* title) {
212221 return changed;
213222}
214223
215- void PCSX::Widgets::MemcardManager::drawIcon (int blockNumber, PCSX ::SIO ::McdBlock& block) {
224+ void PCSX::Widgets::MemcardManager::drawIcon (int blockNumber, const PCSX ::SIO ::McdBlock& block) {
216225 int currentFrame = 0 ; // 1st frame = 0, 2nd frame = 1, 3rd frame = 2 and so on
217226 const auto texture = m_iconTextures[blockNumber - 1 ];
218227 glBindTexture (GL_TEXTURE_2D , texture);
@@ -231,30 +240,7 @@ void PCSX::Widgets::MemcardManager::drawIcon(int blockNumber, PCSX::SIO::McdBloc
231240 glTexSubImage2D (GL_TEXTURE_2D , 0 , 0 , 0 , 16 , 16 , GL_RGBA , GL_UNSIGNED_SHORT_1_5_5_5_REV , icon);
232241 } else {
233242 uint32_t pixels[32 * 32 ];
234- const auto data = m_currentCardData;
235- const auto titleFrame = data + blockNumber * PCSX ::SIO ::MCD_BLOCK_SIZE ;
236-
237- // Calculate icon offset using the header info documented here
238- // https://psx-spx.consoledev.net/pocketstation/#pocketstation-file-headericons
239- int iconOffset = 0x80 + (titleFrame[0x2 ] & 0xf ) * 0x80 ;
240- // iconOffset += ~((titleFrame[0x57] * 8 + 0x7f) & 0x7f);
241- const auto icon = (uint32_t *)(titleFrame + iconOffset);
242-
243- int index = 0 ;
244- for (auto scanline = 0 ; scanline < 32 ; scanline++) {
245- auto line = icon[scanline];
246-
247- for (auto pixel = 0 ; pixel < 32 ; pixel++) {
248- if ((line & 1 ) != 0 ) {
249- pixels[index++] = 0xff ; // Black
250- } else {
251- pixels[index++] = 0xffffffff ; // White
252- }
253-
254- line >>= 1 ; // lsb = next pixel
255- }
256- }
257-
243+ getPocketstationIcon (pixels, blockNumber);
258244 glTexSubImage2D (GL_TEXTURE_2D , 0 , 0 , 0 , 32 , 32 , GL_RGBA , GL_UNSIGNED_BYTE , pixels);
259245 }
260246
@@ -311,3 +297,40 @@ void PCSX::Widgets::MemcardManager::performAction() {
311297
312298 m_pendingAction.type = Actions::None; // Cancel action
313299}
300+
301+ // Extract the pocketstation icon from the block indicated by blockNumber into the pixels array (In RGBA8888)
302+ void PCSX::Widgets::MemcardManager::getPocketstationIcon (uint32_t * pixels, int blockNumber) {
303+ const auto data = m_currentCardData;
304+ const auto titleFrame = data + blockNumber * PCSX ::SIO ::MCD_BLOCK_SIZE ;
305+
306+ // Calculate icon offset using the header info documented here
307+ // https://psx-spx.consoledev.net/pocketstation/#pocketstation-file-headericons
308+ int iconOffset = 0x80 + (titleFrame[0x2 ] & 0xf ) * 0x80 ;
309+ iconOffset += (titleFrame[0x57 ] * 8 + 0x7f ) & ~0x7f ;
310+ const auto icon = (uint32_t *)(titleFrame + iconOffset);
311+
312+ int index = 0 ;
313+ for (auto scanline = 0 ; scanline < 32 ; scanline++) {
314+ auto line = icon[scanline];
315+
316+ for (auto pixel = 0 ; pixel < 32 ; pixel++) {
317+ if ((line & 1 ) != 0 ) {
318+ pixels[index++] = 0xff ; // Black
319+ } else {
320+ pixels[index++] = 0xffffffff ; // White
321+ }
322+
323+ line >>= 1 ; // lsb = next pixel
324+ }
325+ }
326+ }
327+
328+ void PCSX::Widgets::MemcardManager::exportPNG (int blockNumber, const PCSX ::SIO ::McdBlock& block) {
329+ if (m_drawPocketstationIcons) {
330+ uint32_t pixels[32 * 32 ];
331+ getPocketstationIcon (pixels, blockNumber);
332+
333+ const auto filename = fmt::format (" icon{}.png" , blockNumber);
334+ stbi_write_png (filename.c_str (), 32 , 32 , 4 , pixels, 128 ); // Stride = 32 pixels, 4 bytes each, so 128
335+ }
336+ }
0 commit comments