From f951869f64bc84e788b1808809159d6e9d9d9b6b Mon Sep 17 00:00:00 2001 From: dborth Date: Thu, 3 Jun 2010 23:15:58 +0000 Subject: [PATCH] use less memory for snapshot screenshots - so now thumbs are activated for GameCube --- source/fceugx.cpp | 1 + source/fceustate.cpp | 28 +++--------- source/gcvideo.cpp | 12 +---- source/gcvideo.h | 3 +- source/gui/gui.h | 4 +- source/gui/gui_imagedata.cpp | 4 +- source/gui/gui_savebrowser.cpp | 9 ---- source/menu.cpp | 18 +++++--- source/utils/pngu.c | 81 ++++++++++++++++++++++++---------- source/utils/pngu.h | 2 +- 10 files changed, 86 insertions(+), 76 deletions(-) diff --git a/source/fceugx.cpp b/source/fceugx.cpp index a1943f7..a5d7aef 100644 --- a/source/fceugx.cpp +++ b/source/fceugx.cpp @@ -341,6 +341,7 @@ int main(int argc, char *argv[]) DefaultSettings(); // Set defaults InitialiseAudio(); InitFreeType((u8*)font_ttf, font_ttf_size); // Initialize font system + gameScreenPng = (u8 *)malloc(50*1024); InitGUIThreads(); // allocate memory to store rom diff --git a/source/fceustate.cpp b/source/fceustate.cpp index 68516d6..1f381c0 100644 --- a/source/fceustate.cpp +++ b/source/fceustate.cpp @@ -32,35 +32,19 @@ bool SaveState (char * filepath, bool silent) bool retval = false; int datasize; int offset = 0; - int imgSize = 0; // image screenshot bytes written int device; if(!FindDevice(filepath, &device)) return 0; // save screenshot - I would prefer to do this from gameScreenTex - if(gameScreenTex2 != NULL) + if(gameScreenPngSize > 0) { - AllocSaveBuffer (); - - IMGCTX pngContext = PNGU_SelectImageFromBuffer(savebuffer); - - if (pngContext != NULL) - { - imgSize = PNGU_EncodeFromGXTexture(pngContext, vmode->fbWidth, vmode->efbHeight, gameScreenTex2, 0); - PNGU_ReleaseImageContext(pngContext); - } - - if(imgSize > 0) - { - char screenpath[1024]; - strncpy(screenpath, filepath, 1024); - screenpath[strlen(screenpath)-4] = 0; - sprintf(screenpath, "%s.png", screenpath); - SaveFile(screenpath, imgSize, silent); - } - - FreeSaveBuffer (); + char screenpath[1024]; + strncpy(screenpath, filepath, 1024); + screenpath[strlen(screenpath)-4] = 0; + sprintf(screenpath, "%s.png", screenpath); + SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent); } memorystream save(SAVEBUFFERSIZE); diff --git a/source/gcvideo.cpp b/source/gcvideo.cpp index bf69d11..d66157f 100644 --- a/source/gcvideo.cpp +++ b/source/gcvideo.cpp @@ -60,7 +60,8 @@ static int UpdateVideo = 1; static int vmode_60hz = 0; u8 * gameScreenTex = NULL; // a GX texture screen capture of the game -u8 * gameScreenTex2 = NULL; // a GX texture screen capture of the game (copy) +u8 * gameScreenPng = NULL; +int gameScreenPngSize = 0; #define HASPECT 256 #define VASPECT 240 @@ -834,15 +835,6 @@ void TakeScreenshot() GX_CopyTex(gameScreenTex, GX_FALSE); GX_PixModeSync(); DCFlushRange(gameScreenTex, texSize); - - #ifdef HW_RVL - if(gameScreenTex2) free(gameScreenTex2); - gameScreenTex2 = (u8 *)memalign(32, texSize); - if(gameScreenTex2 == NULL) return; - GX_CopyTex(gameScreenTex2, GX_FALSE); - GX_PixModeSync(); - DCFlushRange(gameScreenTex2, texSize); - #endif } /**************************************************************************** diff --git a/source/gcvideo.h b/source/gcvideo.h index 127a308..9003c72 100644 --- a/source/gcvideo.h +++ b/source/gcvideo.h @@ -37,7 +37,8 @@ extern GXRModeObj *vmode; extern int screenheight; extern int screenwidth; extern u8 * gameScreenTex; -extern u8 * gameScreenTex2; +extern u8 * gameScreenPng; +extern int gameScreenPngSize; extern struct st_palettes palettes[]; extern int FDSSwitchRequested; extern bool progressive; diff --git a/source/gui/gui.h b/source/gui/gui.h index 8a37107..3fc1d0b 100644 --- a/source/gui/gui.h +++ b/source/gui/gui.h @@ -538,7 +538,9 @@ class GuiImageData //!Constructor //!Converts the image data to RGBA8 - expects PNG format //!\param i Image data - GuiImageData(const u8 * i); + //!\param w Max image width (0 = not set) + //!\param h Max image height (0 = not set) + GuiImageData(const u8 * i, int w=0, int h=0); //!Destructor ~GuiImageData(); //!Gets a pointer to the image data diff --git a/source/gui/gui_imagedata.cpp b/source/gui/gui_imagedata.cpp index bc2f1e3..41d357c 100644 --- a/source/gui/gui_imagedata.cpp +++ b/source/gui/gui_imagedata.cpp @@ -13,14 +13,14 @@ /** * Constructor for the GuiImageData class. */ -GuiImageData::GuiImageData(const u8 * i) +GuiImageData::GuiImageData(const u8 * i, int maxw, int maxh) { data = NULL; width = 0; height = 0; if(i) - data = DecodePNG(i, &width, &height); + data = DecodePNG(i, &width, &height, maxw, maxh); } /** diff --git a/source/gui/gui_savebrowser.cpp b/source/gui/gui_savebrowser.cpp index 14b8b18..4e46f28 100644 --- a/source/gui/gui_savebrowser.cpp +++ b/source/gui/gui_savebrowser.cpp @@ -327,8 +327,6 @@ void GuiSaveBrowser::Update(GuiTrigger * t) saveType[1]->SetText("State"); savePreviewImg[0]->SetImage(gameSaveBlank); savePreviewImg[1]->SetImage(gameSaveBlank); - savePreviewImg[0]->SetScale(1); - savePreviewImg[1]->SetScale(1); saveBtn[0]->SetVisible(true); saveBtn[1]->SetVisible(true); @@ -367,16 +365,9 @@ void GuiSaveBrowser::Update(GuiTrigger * t) saveType[i]->SetText(savetext); if(saves->previewImg[listOffset+i] != NULL) - { savePreviewImg[i]->SetImage(saves->previewImg[listOffset+i]); - savePreviewImg[i]->SetScale(0.1); - - } else - { savePreviewImg[i]->SetImage(gameSaveBlank); - savePreviewImg[i]->SetScale(1); - } } else { diff --git a/source/menu.cpp b/source/menu.cpp index 7b870d4..dd5bd59 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -1451,6 +1451,7 @@ static int MenuGame() { free(gameScreenTex); gameScreenTex = NULL; + gameScreenPngSize = 0; } bgImg->SetVisible(true); #ifndef NO_SOUND @@ -1653,7 +1654,7 @@ static int MenuGameSaves(int action) memset(savebuffer, 0, SAVEBUFFERSIZE); if(LoadFile(scrfile, SILENT)) - saves.previewImg[j] = new GuiImageData(savebuffer); + saves.previewImg[j] = new GuiImageData(savebuffer, 64, 48); FreeSaveBuffer(); } snprintf(filepath, 1024, "%s%s/%s", pathPrefix[GCSettings.SaveMethod], GCSettings.SaveFolder, saves.filename[j]); @@ -3813,6 +3814,15 @@ MainMenu (int menu) if(gameScreenTex) { + IMGCTX pngContext = PNGU_SelectImageFromBuffer(gameScreenPng); + + if (pngContext != NULL) + { + gameScreenPngSize = PNGU_EncodeFromGXTexture(pngContext, vmode->fbWidth, vmode->efbHeight, gameScreenTex, 0); + PNGU_ReleaseImageContext(pngContext); + DCFlushRange(gameScreenPng, 50*1024); + } + gameScreenImg = new GuiImage(gameScreenTex, vmode->fbWidth, vmode->efbHeight); gameScreenImg->SetAlpha(192); gameScreenImg->ColorStripe(30); @@ -3958,11 +3968,7 @@ MainMenu (int menu) { free(gameScreenTex); gameScreenTex = NULL; - } - if(gameScreenTex2) - { - free(gameScreenTex2); - gameScreenTex2 = NULL; + gameScreenPngSize = 0; } // wait for keys to be depressed diff --git a/source/utils/pngu.c b/source/utils/pngu.c index f621220..57408f5 100644 --- a/source/utils/pngu.c +++ b/source/utils/pngu.c @@ -374,34 +374,56 @@ static inline PNGU_u32 coordsRGBA8(PNGU_u32 x, PNGU_u32 y, PNGU_u32 w) return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1; } -static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u8 default_alpha) +static u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, int * dstWidth, int * dstHeight, int maxWidth, int maxHeight) { - PNGU_u8 *dst; - PNGU_u32 x, y, offset; + PNGU_u8 default_alpha = 255; + u8 *dst; + int x, y, x2, y2, offset; + int xRatio = 0, yRatio = 0; png_byte *pixel; if (pngu_decode (ctx, width, height, 0) != PNGU_OK) return NULL; - PNGU_u32 newWidth = width; - if(newWidth%4) newWidth += (4-newWidth%4); - PNGU_u32 newHeight = height; - if(newHeight%4) newHeight += (4-newHeight%4); + int newWidth = width; + int newHeight = height; - int len = (newWidth * newHeight) << 2; + if((maxWidth > 0 && width > maxWidth) || (maxHeight > 0 && height > maxHeight)) + { + float ratio = (float)width/(float)height; + + newWidth = maxWidth; + newHeight = maxWidth/ratio; + + if(newHeight > maxHeight) + { + newWidth = maxHeight*ratio; + newHeight = maxHeight; + } + xRatio = (int)((width<<16)/newWidth)+1; + yRatio = (int)((height<<16)/newHeight)+1; + } + + int padWidth = newWidth; + int padHeight = newHeight; + if(padWidth%4) padWidth += (4-padWidth%4); + if(padHeight%4) padHeight += (4-padHeight%4); + + int len = (padWidth * padHeight) << 2; if(len%32) len += (32-len%32); + dst = memalign (32, len); if(!dst) return NULL; - for (y = 0; y < newHeight; y++) + for (y = 0; y < padHeight; y++) { - for (x = 0; x < newWidth; x++) + for (x = 0; x < padWidth; x++) { - offset = coordsRGBA8(x, y, newWidth); - - if(y >= height || x >= width) + offset = coordsRGBA8(x, y, padWidth); + + if(y >= newHeight || x >= newWidth) { dst[offset] = 0; dst[offset+1] = 255; @@ -410,10 +432,20 @@ static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 hei } else { + if(xRatio > 0) + { + x2 = ((x*xRatio)>>16); + y2 = ((y*yRatio)>>16); + } + if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA || ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) { - pixel = &(ctx->row_pointers[y][x*4]); + if(xRatio > 0) + pixel = &(ctx->row_pointers[y2][x2*4]); + else + pixel = &(ctx->row_pointers[y][x*4]); + dst[offset] = pixel[3]; // Alpha dst[offset+1] = pixel[0]; // Red dst[offset+32] = pixel[1]; // Green @@ -421,7 +453,11 @@ static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 hei } else { - pixel = &(ctx->row_pointers[y][x*3]); + if(xRatio > 0) + pixel = &(ctx->row_pointers[y2][x2*3]); + else + pixel = &(ctx->row_pointers[y][x*3]); + dst[offset] = default_alpha; // Alpha dst[offset+1] = pixel[0]; // Red dst[offset+32] = pixel[1]; // Green @@ -435,6 +471,8 @@ static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 hei free (ctx->img_data); free (ctx->row_pointers); + *dstWidth = padWidth; + *dstHeight = padHeight; DCFlushRange(dst, len); return dst; } @@ -519,23 +557,18 @@ int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop) return PNGU_OK; } -PNGU_u8 * DecodePNG(const PNGU_u8 *src, int * width, int * height) +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int * width, int * height, int maxwidth, int maxheight) { PNGUPROP imgProp; IMGCTX ctx = PNGU_SelectImageFromBuffer(src); - PNGU_u8 *dst = NULL; + u8 *dst = NULL; if(!ctx) return NULL; if(PNGU_GetImageProperties(ctx, &imgProp) == PNGU_OK) - { - dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, 255); - - *width = imgProp.imgWidth; - *height = imgProp.imgHeight; - } - + dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, width, height, maxwidth, maxheight); + PNGU_ReleaseImageContext (ctx); return dst; } diff --git a/source/utils/pngu.h b/source/utils/pngu.h index 4819fbc..8024b96 100644 --- a/source/utils/pngu.h +++ b/source/utils/pngu.h @@ -67,7 +67,7 @@ int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *fileproperties); * Image conversion * ****************************************************************************/ -PNGU_u8 * DecodePNG(const PNGU_u8 *src, int *width, int *height); +PNGU_u8 * DecodePNG(const PNGU_u8 *src, int *width, int *height, int maxwidth, int maxheight); int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride); int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride);