mirror of
https://github.com/dborth/snes9xgx.git
synced 2024-11-01 08:25:18 +01:00
use less memory for snapshot screenshots - so now thumbs are activated for GameCube
This commit is contained in:
parent
2ffdd76b7c
commit
118ca267c5
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user