use less memory for snapshot screenshots - so now thumbs are activated for GameCube

This commit is contained in:
dborth 2010-06-03 23:15:34 +00:00
parent 2ffdd76b7c
commit 118ca267c5
10 changed files with 89 additions and 78 deletions

View File

@ -43,35 +43,19 @@ void S9xCloseSnapshotFile(STREAM s)
int int
SaveSnapshot (char * filepath, bool silent) SaveSnapshot (char * filepath, bool silent)
{ {
int imgSize = 0; // image screenshot bytes written
int device; int device;
if(!FindDevice(filepath, &device)) if(!FindDevice(filepath, &device))
return 0; return 0;
// save screenshot - I would prefer to do this from gameScreenTex // save screenshot
if(gameScreenTex2 != NULL) if(gameScreenPngSize > 0)
{ {
AllocSaveBuffer (); char screenpath[1024];
strncpy(screenpath, filepath, 1024);
IMGCTX pngContext = PNGU_SelectImageFromBuffer(savebuffer); screenpath[strlen(screenpath)-4] = 0;
sprintf(screenpath, "%s.png", screenpath);
if (pngContext != NULL) SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent);
{
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 ();
} }
STREAM fp = OPEN_STREAM(filepath, "wb"); STREAM fp = OPEN_STREAM(filepath, "wb");

View File

@ -538,7 +538,9 @@ class GuiImageData
//!Constructor //!Constructor
//!Converts the image data to RGBA8 - expects PNG format //!Converts the image data to RGBA8 - expects PNG format
//!\param i Image data //!\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 //!Destructor
~GuiImageData(); ~GuiImageData();
//!Gets a pointer to the image data //!Gets a pointer to the image data

View File

@ -13,14 +13,14 @@
/** /**
* Constructor for the GuiImageData class. * Constructor for the GuiImageData class.
*/ */
GuiImageData::GuiImageData(const u8 * i) GuiImageData::GuiImageData(const u8 * i, int maxw, int maxh)
{ {
data = NULL; data = NULL;
width = 0; width = 0;
height = 0; height = 0;
if(i) if(i)
data = DecodePNG(i, &width, &height); data = DecodePNG(i, &width, &height, maxw, maxh);
} }
/** /**

View File

@ -327,8 +327,6 @@ void GuiSaveBrowser::Update(GuiTrigger * t)
saveType[1]->SetText("Snapshot"); saveType[1]->SetText("Snapshot");
savePreviewImg[0]->SetImage(gameSaveBlank); savePreviewImg[0]->SetImage(gameSaveBlank);
savePreviewImg[1]->SetImage(gameSaveBlank); savePreviewImg[1]->SetImage(gameSaveBlank);
savePreviewImg[0]->SetScale(1);
savePreviewImg[1]->SetScale(1);
saveBtn[0]->SetVisible(true); saveBtn[0]->SetVisible(true);
saveBtn[1]->SetVisible(true); saveBtn[1]->SetVisible(true);
@ -367,16 +365,9 @@ void GuiSaveBrowser::Update(GuiTrigger * t)
saveType[i]->SetText(savetext); saveType[i]->SetText(savetext);
if(saves->previewImg[listOffset+i] != NULL) if(saves->previewImg[listOffset+i] != NULL)
{
savePreviewImg[i]->SetImage(saves->previewImg[listOffset+i]); savePreviewImg[i]->SetImage(saves->previewImg[listOffset+i]);
savePreviewImg[i]->SetScale(0.1);
}
else else
{
savePreviewImg[i]->SetImage(gameSaveBlank); savePreviewImg[i]->SetImage(gameSaveBlank);
savePreviewImg[i]->SetScale(1);
}
} }
else else
{ {

View File

@ -1444,6 +1444,7 @@ static int MenuGame()
{ {
free(gameScreenTex); free(gameScreenTex);
gameScreenTex = NULL; gameScreenTex = NULL;
gameScreenPngSize = 0;
} }
bgImg->SetVisible(true); bgImg->SetVisible(true);
#ifndef NO_SOUND #ifndef NO_SOUND
@ -1645,7 +1646,7 @@ static int MenuGameSaves(int action)
memset(savebuffer, 0, SAVEBUFFERSIZE); memset(savebuffer, 0, SAVEBUFFERSIZE);
if(LoadFile(scrfile, SILENT)) if(LoadFile(scrfile, SILENT))
saves.previewImg[j] = new GuiImageData(savebuffer); saves.previewImg[j] = new GuiImageData(savebuffer, 64, 48);
} }
snprintf(filepath, 1024, "%s%s/%s", pathPrefix[GCSettings.SaveMethod], GCSettings.SaveFolder, saves.filename[j]); snprintf(filepath, 1024, "%s%s/%s", pathPrefix[GCSettings.SaveMethod], GCSettings.SaveFolder, saves.filename[j]);
if (stat(filepath, &filestat) == 0) if (stat(filepath, &filestat) == 0)
@ -3769,6 +3770,15 @@ MainMenu (int menu)
if(gameScreenTex) 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 = new GuiImage(gameScreenTex, vmode->fbWidth, vmode->efbHeight);
gameScreenImg->SetAlpha(192); gameScreenImg->SetAlpha(192);
gameScreenImg->ColorStripe(30); gameScreenImg->ColorStripe(30);
@ -3915,11 +3925,7 @@ MainMenu (int menu)
{ {
free(gameScreenTex); free(gameScreenTex);
gameScreenTex = NULL; gameScreenTex = NULL;
} gameScreenPngSize = 0;
if(gameScreenTex2)
{
free(gameScreenTex2);
gameScreenTex2 = NULL;
} }
// wait for keys to be depressed // wait for keys to be depressed

View File

@ -456,6 +456,8 @@ main(int argc, char *argv[])
// Initialize font system // Initialize font system
InitFreeType((u8*)font_ttf, font_ttf_size); InitFreeType((u8*)font_ttf, font_ttf_size);
gameScreenPng = (u8 *)malloc(50*1024);
InitGUIThreads(); InitGUIThreads();
emulate(); // main loop emulate(); // main loop

View File

@ -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; 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_u8 default_alpha = 255;
PNGU_u32 x, y, offset; u8 *dst;
int x, y, x2, y2, offset;
int xRatio = 0, yRatio = 0;
png_byte *pixel; png_byte *pixel;
if (pngu_decode (ctx, width, height, 0) != PNGU_OK) if (pngu_decode (ctx, width, height, 0) != PNGU_OK)
return NULL; return NULL;
PNGU_u32 newWidth = width; int newWidth = width;
if(newWidth%4) newWidth += (4-newWidth%4); int newHeight = height;
PNGU_u32 newHeight = height;
if(newHeight%4) newHeight += (4-newHeight%4);
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); if(len%32) len += (32-len%32);
dst = memalign (32, len); dst = memalign (32, len);
if(!dst) if(!dst)
return NULL; 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); offset = coordsRGBA8(x, y, padWidth);
if(y >= height || x >= width) if(y >= newHeight || x >= newWidth)
{ {
dst[offset] = 0; dst[offset] = 0;
dst[offset+1] = 255; dst[offset+1] = 255;
@ -410,10 +432,20 @@ static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 hei
} }
else else
{ {
if(xRatio > 0)
{
x2 = ((x*xRatio)>>16);
y2 = ((y*yRatio)>>16);
}
if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA || if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA ||
ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_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] = pixel[3]; // Alpha
dst[offset+1] = pixel[0]; // Red dst[offset+1] = pixel[0]; // Red
dst[offset+32] = pixel[1]; // Green dst[offset+32] = pixel[1]; // Green
@ -421,7 +453,11 @@ static PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 hei
} }
else 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] = default_alpha; // Alpha
dst[offset+1] = pixel[0]; // Red dst[offset+1] = pixel[0]; // Red
dst[offset+32] = pixel[1]; // Green 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->img_data);
free (ctx->row_pointers); free (ctx->row_pointers);
*dstWidth = padWidth;
*dstHeight = padHeight;
DCFlushRange(dst, len); DCFlushRange(dst, len);
return dst; return dst;
} }
@ -519,22 +557,17 @@ int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *imgprop)
return PNGU_OK; 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; PNGUPROP imgProp;
IMGCTX ctx = PNGU_SelectImageFromBuffer(src); IMGCTX ctx = PNGU_SelectImageFromBuffer(src);
PNGU_u8 *dst = NULL; u8 *dst = NULL;
if(!ctx) if(!ctx)
return NULL; return NULL;
if(PNGU_GetImageProperties(ctx, &imgProp) == PNGU_OK) if(PNGU_GetImageProperties(ctx, &imgProp) == PNGU_OK)
{ dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, width, height, maxwidth, maxheight);
dst = PNGU_DecodeTo4x4RGBA8 (ctx, imgProp.imgWidth, imgProp.imgHeight, 255);
*width = imgProp.imgWidth;
*height = imgProp.imgHeight;
}
PNGU_ReleaseImageContext (ctx); PNGU_ReleaseImageContext (ctx);
return dst; return dst;

View File

@ -67,7 +67,7 @@ int PNGU_GetImageProperties (IMGCTX ctx, PNGUPROP *fileproperties);
* Image conversion * * 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_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); int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride);

View File

@ -61,7 +61,8 @@ static Mtx GXmodelView2D;
static int vwidth, vheight, oldvwidth, oldvheight; static int vwidth, vheight, oldvwidth, oldvheight;
u8 * gameScreenTex = NULL; // a GX texture screen capture of the game 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;
u32 FrameTimer = 0; u32 FrameTimer = 0;
@ -890,15 +891,6 @@ void TakeScreenshot()
GX_CopyTex(gameScreenTex, GX_FALSE); GX_CopyTex(gameScreenTex, GX_FALSE);
GX_PixModeSync(); GX_PixModeSync();
DCFlushRange(gameScreenTex, texSize); 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
} }
/**************************************************************************** /****************************************************************************

View File

@ -35,7 +35,8 @@ extern int screenheight;
extern int screenwidth; extern int screenwidth;
extern bool progressive; extern bool progressive;
extern u8 * gameScreenTex; extern u8 * gameScreenTex;
extern u8 * gameScreenTex2; extern u8 * gameScreenPng;
extern int gameScreenPngSize;
extern u32 FrameTimer; extern u32 FrameTimer;
extern u8 vmode_60hz; extern u8 vmode_60hz;
extern int timerstyle; extern int timerstyle;