RomInfoWidget now honours 1x and 2x mode, and correctly resizes PNG

snapshots to the selected mode.  This means that you no longer have
to make sure that snapshots are taken in 1x mode (as was the previous
functionality).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1585 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2008-12-30 02:34:49 +00:00
parent c5de58f13c
commit 8ba2482f50
4 changed files with 97 additions and 36 deletions

View File

@ -749,8 +749,9 @@
</tr>
<tr>
<td><pre>-romviewer &lt;1|0&gt;</pre></td>
<td>Show/hide ROM info viewer in ROM launcher mode.</td>
<td><pre>-romviewer &lt;0|1|2&gt;</pre></td>
<td>Hide ROM info viewer in ROM launcher mode (0), or use the
given zoom level (1 or 2).</td>
</tr>
<tr>

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: LauncherDialog.cxx,v 1.90 2008-12-29 20:42:15 stephena Exp $
// $Id: LauncherDialog.cxx,v 1.91 2008-12-30 02:34:49 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -82,9 +82,9 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
int romWidth = 0;
int romSize = instance().settings().getInt("romviewer");
if(romSize > 1 && w >= 1000 && h >= 800)
romWidth = 375*2;
romWidth = 660;
else if(romSize > 0 && w >= 640 && h >= 480)
romWidth = 375;
romWidth = 365;
int listWidth = _w - (romWidth > 0 ? romWidth+25 : 20);
myList = new StringListWidget(this, font, xpos, ypos,

View File

@ -13,10 +13,11 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RomInfoWidget.cxx,v 1.11 2008-12-29 20:42:15 stephena Exp $
// $Id: RomInfoWidget.cxx,v 1.12 2008-12-30 02:34:49 stephena Exp $
//============================================================================
#include <cstring>
#include <cmath>
#include <zlib.h>
#include "FrameBuffer.hxx"
@ -33,6 +34,7 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
: Widget(boss, font, x, y, w, h),
mySurface(NULL),
mySurfaceID(-1),
myZoomLevel(w > 400 ? 2 : 1),
mySurfaceIsValid(false),
myHaveProperties(false)
{
@ -94,7 +96,8 @@ void RomInfoWidget::parseProperties()
mySurface = instance().frameBuffer().surface(mySurfaceID);
if(mySurface == NULL)
{
mySurfaceID = instance().frameBuffer().allocateSurface(320, 260, false);
mySurfaceID = instance().frameBuffer().allocateSurface(
320*myZoomLevel, 260*myZoomLevel, false);
mySurface = instance().frameBuffer().surface(mySurfaceID);
}
@ -140,14 +143,11 @@ void RomInfoWidget::parseProperties()
{
if(!parseIHDR(width, height, data, size))
throw "Invalid PNG image (IHDR)";
mySurface->setWidth(width);
mySurface->setHeight(height);
}
else if(type == "IDAT")
{
if(!parseIDATChunk(mySurface, width, height, data, size))
throw "PNG image too large";
throw "Invalid PNG image (IDAT)";
}
else if(type == "tEXt")
textChucks.push_back(parseTextChunk(data, size));
@ -188,24 +188,27 @@ void RomInfoWidget::drawWidget(bool hilite)
{
FBSurface& s = dialog().surface();
const int yoff = myZoomLevel > 1 ? 260*2 + 10 : 275;
s.fillRect(_x+2, _y+2, _w-4, _h-4, kWidColor);
s.box(_x, _y, _w, _h, kColor, kShadowColor);
s.box(_x, _y+275, _w, _h-275, kColor, kShadowColor);
s.box(_x, _y+yoff, _w, _h-yoff, kColor, kShadowColor);
if(!myHaveProperties) return;
if(mySurfaceIsValid)
{
uInt32 x = ((_w - mySurface->getWidth()) >> 1) + getAbsX();
uInt32 y = ((275 - mySurface->getHeight()) >> 1) + getAbsY();
uInt32 x = _x + ((_w - mySurface->getWidth()) >> 1);
uInt32 y = _y + ((yoff - mySurface->getHeight()) >> 1);
s.drawSurface(mySurface, x, y);
}
else if(mySurfaceErrorMsg != "")
{
int x = _x + ((_w - _font->getStringWidth(mySurfaceErrorMsg)) >> 1);
s.drawString(_font, mySurfaceErrorMsg, x, 120, _w - 10, _textcolor);
uInt32 x = _x + ((_w - _font->getStringWidth(mySurfaceErrorMsg)) >> 1);
uInt32 y = _y + ((yoff - _font->getLineHeight()) >> 1);
s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor);
}
int xpos = _x + 5, ypos = _y + 280 + 5;
int xpos = _x + 5, ypos = _y + yoff + 10;
for(unsigned int i = 0; i < myRomInfo.size(); ++i)
{
s.drawString(_font, myRomInfo[i], xpos, ypos, _w - 10, _textcolor);
@ -257,10 +260,6 @@ bool RomInfoWidget::parseIHDR(int& width, int& height, uInt8* data, int size)
width = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
height = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
// Make sure image can fit in widget bounds
width = BSPF_min(320, width);
height = BSPF_min(260, height);
uInt8 trailer[5] = { 8, 2, 0, 0, 0 }; // 24-bit RGB
return memcmp(trailer, data + 8, 5) == 0;
}
@ -269,23 +268,81 @@ bool RomInfoWidget::parseIHDR(int& width, int& height, uInt8* data, int size)
bool RomInfoWidget::parseIDATChunk(FBSurface* surface, int width, int height,
uInt8* data, int size)
{
// The entire decompressed image data
uLongf bufsize = (width * 3 + 1) * height;
uInt8* buffer = new uInt8[bufsize];
// Figure out the original zoom level of the snapshot
// All snapshots generated by Stella are at most some multiple of 320
// pixels wide
// The only complication is when the aspect ratio is changed, the width
// can range from 256 (80%) to 320 (100%)
// The following calculation will work up to approx. 16x zoom level,
// but since Stella only generates snapshots at up to 10x, we should
// be fine for a while ...
uInt32 izoom = int(ceil(width/320.0));
// Set the surface size
uInt32 sw = width / izoom * myZoomLevel,
sh = height / izoom * myZoomLevel;
mySurface->setWidth(sw);
mySurface->setHeight(sh);
// Decompress the image, and scale it correctly
uInt32 ipitch = width * 3 + 1, // bytes per line of the actual PNG image
spitch = sw * 3; // bytes per line of the surface/line
uLongf bufsize = ipitch * height;
uInt8* buffer = new uInt8[bufsize];
uInt8* line = new uInt8[spitch + myZoomLevel*3]; // few extra bytes for rounding issues
int pitch = width * 3; // bytes per line of the image
if(uncompress(buffer, &bufsize, data, size) == Z_OK)
{
uInt8* buf_ptr = buffer;
for(int row = 0; row < height; row++, buf_ptr += pitch)
uInt8* buf_ptr = buffer + 1; // skip past first column (PNG filter type)
uInt32 buf_offset = ipitch * izoom;
uInt32 i_offset = 3 * izoom;
uInt32 srow = 0;
/*
cerr << "surface:" << endl
<< " w = " << sw << endl
<< " h = " << sh << endl
<< " szoom = " << myZoomLevel << endl
<< " spitch = " << spitch << endl
<< endl;
cerr << "image:" << endl
<< " width = " << width << endl
<< " height = " << height << endl
<< " izoom = " << izoom << endl
<< " ipitch = " << ipitch << endl
<< " bufsize = " << bufsize << endl
<< " buf_offset = " << buf_offset << endl
<< " i_offset = " << i_offset << endl
<< endl;
*/
// Grab each non-duplicate row of data from the image
for(int irow = 0; irow < height; irow += izoom, buf_ptr += buf_offset)
{
buf_ptr++; // skip past first byte (PNG filter type)
surface->drawBytes(buf_ptr, 0, row, pitch);
// Scale the image data into the temporary line buffer
uInt8* i_ptr = buf_ptr;
uInt8* l_ptr = line;
for(int icol = 0; icol < width; icol += izoom, i_ptr += i_offset)
{
uInt32 xstride = myZoomLevel;
while(xstride--)
{
*l_ptr++ = *i_ptr;
*l_ptr++ = *(i_ptr+1);
*l_ptr++ = *(i_ptr+2);
}
}
// Then fill the surface with those bytes
uInt32 ystride = myZoomLevel;
while(ystride--)
surface->drawBytes(line, 0, srow++, spitch);
}
delete[] buffer;
delete[] line;
return true;
}
delete[] buffer;
delete[] line;
return false;
}

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: RomInfoWidget.hxx,v 1.6 2008-12-29 20:42:15 stephena Exp $
// $Id: RomInfoWidget.hxx,v 1.7 2008-12-30 02:34:49 stephena Exp $
//============================================================================
#ifndef ROM_INFO_WIDGET_HXX
@ -44,18 +44,21 @@ class RomInfoWidget : public Widget
private:
void parseProperties();
static bool isValidPNGHeader(uInt8* header);
static void readPNGChunk(ifstream& in, string& type, uInt8** data, int& size);
static bool parseIHDR(int& width, int& height, uInt8* data, int size);
static bool parseIDATChunk(FBSurface* surface, int width, int height,
uInt8* data, int size);
static string parseTextChunk(uInt8* data, int size);
bool isValidPNGHeader(uInt8* header);
void readPNGChunk(ifstream& in, string& type, uInt8** data, int& size);
bool parseIHDR(int& width, int& height, uInt8* data, int size);
bool parseIDATChunk(FBSurface* surface, int width, int height,
uInt8* data, int size);
string parseTextChunk(uInt8* data, int size);
private:
// Surface id and pointer holding the scaled PNG image
FBSurface* mySurface;
int mySurfaceID;
// How much to zoom the PNG image
int myZoomLevel;
// Whether the surface should be redrawn by drawWidget()
bool mySurfaceIsValid;