OK, I originally intended to fix FrameBuffer::scanline for SDL2,

which I though a just a one or two-liner equivalent to glReadPixels.
Turns out that SDL2 doesn't return 24-bit RGB data (only 16 or 32-bit),
so the PNGLibrary had to massage the data.  In the process, converted
the PNG saving functions to actually use PNG library functions, which
greatly simplified converting packing from 32 -> 24-bit.  Historically,
the PNG save functions were written before libpng was a requirement,
so they were hand-rolled.  Once libpng was integrated into the codebase,
it didn't make much sense to not use it anymore.

So an expected two-line code fix became this commit ...


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2919 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2014-06-13 13:35:41 +00:00
parent a0aa1c8e0a
commit d275773413
10 changed files with 245 additions and 235 deletions

View File

@ -234,15 +234,12 @@ FBSurface* FrameBufferSDL2::createSurface(uInt32 w, uInt32 h,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSDL2::scanline(uInt32 row, uInt8* data) const
void FrameBufferSDL2::readPixels(const GUI::Rect& rect,
uInt8* pixels, uInt32 pitch) const
{
#if 0 //FIXSDL
// Invert the row, since OpenGL rows start at the bottom
// of the framebuffer
const GUI::Rect& image = imageRect();
row = image.height() + image.y() - row - 1;
SDL_Rect r;
r.x = rect.x(); r.y = rect.y();
r.w = rect.width(); r.h = rect.height();
p_gl.PixelStorei(GL_PACK_ALIGNMENT, 1);
p_gl.ReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data);
#endif
SDL_RenderReadPixels(myRenderer, &r, SDL_PIXELFORMAT_ARGB8888, pixels, pitch);
}

View File

@ -96,12 +96,16 @@ class FrameBufferSDL2 : public FrameBuffer
bool isDoubleBuffered() const { return myDblBufferedFlag; }
/**
This method is called to get the specified scanline data.
This method is called to get the specified ARGB data from the viewable
FrameBuffer area. Note that this isn't the same as any internal
surfaces that may be in use; it should return the actual data as it
is currently seen onscreen.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
@param rect The bounding rectangle for the buffer
@param buffer The actual pixel data in ARGB8888 format
@param pitch The pitch (in bytes) for the pixel data
*/
void scanline(uInt32 row, uInt8* data) const;
void readPixels(const GUI::Rect& rect, uInt8* buffer, uInt32 pitch) const;
protected:
//////////////////////////////////////////////////////////////////////

View File

@ -17,7 +17,6 @@
// $Id$
//============================================================================
#include <zlib.h>
#include <fstream>
#include <cstring>
#include <sstream>
@ -31,7 +30,8 @@
#include "PNGLibrary.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::PNGLibrary()
PNGLibrary::PNGLibrary(const FrameBuffer& fb)
: myFB(fb)
{
}
@ -44,10 +44,9 @@ PNGLibrary::~PNGLibrary()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PNGLibrary::loadImage(const string& filename,
const FrameBuffer& fb, FBSurface& surface)
void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
{
#define readImageERROR(s) { err_message = s; goto done; }
#define loadImageERROR(s) { err_message = s; goto done; }
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
@ -57,18 +56,18 @@ bool PNGLibrary::loadImage(const string& filename,
ifstream in(filename.c_str(), ios_base::binary);
if(!in.is_open())
readImageERROR("No image found");
loadImageERROR("No image found");
// Create the PNG loading context structure
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
png_user_error, png_user_warn);
if(png_ptr == NULL)
readImageERROR("Couldn't allocate memory for PNG file");
loadImageERROR("Couldn't allocate memory for PNG file");
// Allocate/initialize the memory for image information. REQUIRED.
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
readImageERROR("Couldn't create image information for PNG file");
loadImageERROR("Couldn't create image information for PNG file");
// Set up the input control
png_set_read_fn(png_ptr, &in, png_read_data);
@ -92,20 +91,20 @@ bool PNGLibrary::loadImage(const string& filename,
}
else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
readImageERROR("Greyscale PNG images not supported");
loadImageERROR("Greyscale PNG images not supported");
}
else if(color_type == PNG_COLOR_TYPE_PALETTE)
{
readImageERROR("Paletted PNG images not supported");
png_set_palette_to_rgb(png_ptr);
}
else if(color_type != PNG_COLOR_TYPE_RGB)
{
readImageERROR("Unknown format in PNG image");
loadImageERROR("Unknown format in PNG image");
}
// Create/initialize storage area for the current image
if(!allocateStorage(iwidth, iheight))
readImageERROR("Not enough memory to read PNG file");
loadImageERROR("Not enough memory to read PNG file");
// The PNG read function expects an array of rows, not a single 1-D array
for(uInt32 irow = 0, offset = 0; irow < ReadInfo.height; ++irow, offset += ReadInfo.pitch)
@ -118,7 +117,7 @@ bool PNGLibrary::loadImage(const string& filename,
png_read_end(png_ptr, info_ptr);
// Scale image to surface dimensions
scaleImagetoSurface(fb, surface);
scaleImagetoSurface(surface);
// Cleanup
done:
@ -127,61 +126,136 @@ done:
if(err_message)
throw err_message;
else
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PNGLibrary::saveImage(const string& filename,
const FrameBuffer& framebuffer,
const Properties& props)
void PNGLibrary::saveImage(const string& filename, const Properties& props)
{
#define saveImageERROR(s) { err_message = s; goto done; }
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
const char* err_message = NULL;
const GUI::Rect& imageR = myFB.imageRect();
png_uint_32 width = imageR.width(), height = imageR.height();
png_bytep image = new png_byte[width * height * 4];
png_bytep row_pointers[height];
ofstream out(filename.c_str(), ios_base::binary);
if(!out.is_open())
return "ERROR: Couldn't create snapshot file";
saveImageERROR("ERROR: Couldn't create snapshot file");
// Create the PNG saving context structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
png_user_error, png_user_warn);
if(png_ptr == NULL)
saveImageERROR("Couldn't allocate memory for PNG file");
// Get actual image dimensions. which are not always the same
// as the framebuffer dimensions
const GUI::Rect& image = framebuffer.imageRect();
uInt32 width = image.width(), height = image.height(),
pitch = width * 3;
uInt8* buffer = new uInt8[(pitch + 1) * height];
// Allocate/initialize the memory for image information. REQUIRED.
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
saveImageERROR("Couldn't create image information for PNG file");
// Fill the buffer with scanline data
uInt8* buf_ptr = buffer;
for(uInt32 row = 0; row < height; row++)
{
*buf_ptr++ = 0; // first byte of row is filter type
framebuffer.scanline(row, buf_ptr); // get another scanline
buf_ptr += pitch; // add pitch
}
// Set up the output control
png_set_write_fn(png_ptr, &out, png_write_data, png_io_flush);
return saveBufferToPNG(out, buffer, width, height, props,
framebuffer.tiaSurface().effectsInfo());
// Write PNG header info
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
// Write comments
writeComments(png_ptr, info_ptr, props);
// Write the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
// Pack pixels into bytes
png_set_packing(png_ptr);
// Swap location of alpha bytes from ARGB to RGBA
png_set_swap_alpha(png_ptr);
// Pack ARGB into RGB
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
// Flip BGR pixels to RGB
png_set_bgr(png_ptr);
// Get framebuffer surface pixel data (we get ABGR format)
myFB.readPixels(imageR, image, width*4);
// Set up pointers into "image" byte array
for(png_uint_32 k = 0; k < height; ++k)
row_pointers[k] = image + k*width*4;
// Write the entire image in one go
png_write_image(png_ptr, row_pointers);
// We're finished writing
png_write_end(png_ptr, info_ptr);
// Cleanup
done:
if(png_ptr)
png_destroy_write_struct(&png_ptr, &info_ptr);
if(image)
delete[] image;
if(err_message)
throw err_message;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PNGLibrary::saveImage(const string& filename,
const FrameBuffer& framebuffer, const TIA& tia,
const Properties& props)
void PNGLibrary::saveImage(const string& filename, const TIA& tia,
const Properties& props)
{
ofstream out(filename.c_str(), ios_base::binary);
if(!out.is_open())
return "ERROR: Couldn't create snapshot file";
#define saveImageERROR(s) { err_message = s; goto done; }
uInt32 width = tia.width(), height = tia.height();
uInt8* buffer = new uInt8[(width*3*2 + 1) * height];
// Fill the buffer with pixels from the mediasrc
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
const char* err_message = NULL;
png_uint_32 tiaw = tia.width(), width = tiaw*2, height = tia.height();
png_bytep image = new png_byte[width * height * 3];
png_bytep row_pointers[height];
uInt8 r, g, b;
uInt8* buf_ptr = buffer;
uInt8* buf_ptr = image;
ofstream out(filename.c_str(), ios_base::binary);
if(!out.is_open())
saveImageERROR("ERROR: Couldn't create snapshot file");
// Create the PNG saving context structure
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
png_user_error, png_user_warn);
if(png_ptr == NULL)
saveImageERROR("Couldn't allocate memory for PNG file");
// Allocate/initialize the memory for image information. REQUIRED.
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
saveImageERROR("Couldn't create image information for PNG file");
// Set up the output control
png_set_write_fn(png_ptr, &out, png_write_data, png_io_flush);
// Write PNG header info
png_set_IHDR(png_ptr, info_ptr, width, height, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
// Write comments
writeComments(png_ptr, info_ptr, props);
// Write the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
// Fill the buffer with pixels from the tia, scaled 2x horizontally
for(uInt32 y = 0; y < height; ++y)
{
*buf_ptr++ = 0; // first byte of row is filter type
for(uInt32 x = 0; x < width; ++x)
for(uInt32 x = 0; x < tiaw; ++x)
{
uInt32 pixel = framebuffer.tiaSurface().pixel(y*width+x);
framebuffer.getRGB(pixel, &r, &g, &b);
uInt32 pixel = myFB.tiaSurface().pixel(y*tiaw+x);
myFB.getRGB(pixel, &r, &g, &b);
*buf_ptr++ = r;
*buf_ptr++ = g;
*buf_ptr++ = b;
@ -189,80 +263,24 @@ string PNGLibrary::saveImage(const string& filename,
*buf_ptr++ = g;
*buf_ptr++ = b;
}
// Set up pointers into "image" byte array
buf_ptr = row_pointers[y] = image + y*width*3;
}
return saveBufferToPNG(out, buffer, width << 1, height, props,
framebuffer.tiaSurface().effectsInfo());
}
// Write the entire image in one go
png_write_image(png_ptr, row_pointers);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PNGLibrary::saveBufferToPNG(ofstream& out, uInt8* buffer,
uInt32 width, uInt32 height,
const Properties& props,
const string& effectsInfo)
{
uInt8* compmem = (uInt8*) NULL;
// We're finished writing
png_write_end(png_ptr, info_ptr);
try
{
// PNG file header
uInt8 header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
out.write((const char*)header, 8);
// PNG IHDR
uInt8 ihdr[13];
ihdr[0] = width >> 24; // width
ihdr[1] = width >> 16;
ihdr[2] = width >> 8;
ihdr[3] = width & 0xFF;
ihdr[4] = height >> 24; // height
ihdr[5] = height >> 16;
ihdr[6] = height >> 8;
ihdr[7] = height & 0xFF;
ihdr[8] = 8; // 8 bits per sample (24 bits per pixel)
ihdr[9] = 2; // PNG_COLOR_TYPE_RGB
ihdr[10] = 0; // PNG_COMPRESSION_TYPE_DEFAULT
ihdr[11] = 0; // PNG_FILTER_TYPE_DEFAULT
ihdr[12] = 0; // PNG_INTERLACE_NONE
writePNGChunk(out, "IHDR", ihdr, 13);
// Compress the data with zlib
uLongf compmemsize = (uLongf)((height * (width + 1) * 3 * 1.001 + 1) + 12);
compmem = new uInt8[compmemsize];
if(compmem == NULL ||
(compress(compmem, &compmemsize, buffer, height * (width * 3 + 1)) != Z_OK))
throw "ERROR: Couldn't compress PNG";
// Write the compressed framebuffer data
writePNGChunk(out, "IDAT", compmem, compmemsize);
// Add some info about this snapshot
ostringstream text;
text << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
<< BSPF_ARCH << "]";
writePNGText(out, "Software", text.str());
writePNGText(out, "ROM Name", props.get(Cartridge_Name));
writePNGText(out, "ROM MD5", props.get(Cartridge_MD5));
writePNGText(out, "TV Effects", effectsInfo);
// Finish up
writePNGChunk(out, "IEND", 0, 0);
// Clean up
if(buffer) delete[] buffer;
if(compmem) delete[] compmem;
out.close();
return "Snapshot saved";
}
catch(const char* msg)
{
if(buffer) delete[] buffer;
if(compmem) delete[] compmem;
out.close();
return msg;
}
// Cleanup
done:
if(png_ptr)
png_destroy_write_struct(&png_ptr, &info_ptr);
if(image)
delete[] image;
if(err_message)
throw err_message;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -308,7 +326,7 @@ bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface)
void PNGLibrary::scaleImagetoSurface(FBSurface& surface)
{
// Figure out the original zoom level of the snapshot
// All snapshots generated by Stella are at most some multiple of 320
@ -345,7 +363,7 @@ void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface)
uInt32* l_ptr = ReadInfo.line;
for(uInt32 icol = 0; icol < ReadInfo.width; icol += izoom, i_ptr += i_offset)
{
uInt32 pixel = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
uInt32 pixel = myFB.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));
uInt32 xstride = szoom;
while(xstride--)
*l_ptr++ = pixel;
@ -359,50 +377,30 @@ void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::writePNGChunk(ofstream& out, const char* type,
uInt8* data, int size)
void PNGLibrary::writeComments(png_structp png_ptr, png_infop info_ptr,
const Properties& props)
{
// Stuff the length/type into the buffer
uInt8 temp[8];
temp[0] = size >> 24;
temp[1] = size >> 16;
temp[2] = size >> 8;
temp[3] = size;
temp[4] = type[0];
temp[5] = type[1];
temp[6] = type[2];
temp[7] = type[3];
// Pre-processor voodoo to make the code shorter
#define CONVERT_TO_PNGTEXT(_idx, _key, _text) \
char key##_idx[] = _key; \
char text##_idx[256]; \
strncpy(text##_idx, _text.c_str(), 255); \
text_ptr[_idx].key = key##_idx; \
text_ptr[_idx].text = text##_idx; \
text_ptr[_idx].compression = PNG_TEXT_COMPRESSION_NONE; \
text_ptr[_idx].text_length = 0;
// Write the header
out.write((const char*)temp, 8);
ostringstream version;
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
<< BSPF_ARCH << "]";
// Append the actual data
uInt32 crc = crc32(0, temp + 4, 4);
if(size > 0)
{
out.write((const char*)data, size);
crc = crc32(crc, data, size);
}
png_text text_ptr[4];
CONVERT_TO_PNGTEXT(0, "Software", version.str());
CONVERT_TO_PNGTEXT(1, "ROM Name", props.get(Cartridge_Name));
CONVERT_TO_PNGTEXT(2, "ROM MD5", props.get(Cartridge_MD5));
CONVERT_TO_PNGTEXT(3, "TV Effects", myFB.tiaSurface().effectsInfo());
// Write the CRC
temp[0] = crc >> 24;
temp[1] = crc >> 16;
temp[2] = crc >> 8;
temp[3] = crc;
out.write((const char*)temp, 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PNGLibrary::writePNGText(ofstream& out, const string& key, const string& text)
{
int length = key.length() + 1 + text.length() + 1;
uInt8* data = new uInt8[length];
strcpy((char*)data, key.c_str());
strcpy((char*)data + key.length() + 1, text.c_str());
writePNGChunk(out, "tEXt", data, length-1);
delete[] data;
png_set_text(png_ptr, info_ptr, text_ptr, 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -40,7 +40,7 @@ class TIA;
class PNGLibrary
{
public:
PNGLibrary();
PNGLibrary(const FrameBuffer& fb);
virtual ~PNGLibrary();
/**
@ -48,39 +48,44 @@ class PNGLibrary
scaling the image to the surface bounds.
@param filename The filename to load the PNG image
@param fb The main framebuffer of the application
@param surface The FBSurface into which to place the PNG data
@return On success, the FBSurface containing image data and a
result of true, otherwise a const char* exception is thrown
containing a more detailed error message.
@return On success, the FBSurface containing image data, otherwise a
const char* exception is thrown containing a more detailed
error message.
*/
bool loadImage(const string& filename, const FrameBuffer& fb, FBSurface& surface);
void loadImage(const string& filename, FBSurface& surface);
/**
Save the current TIA image to a PNG file using data from the Framebuffer.
Any postprocessing/filtering will be included.
Save the current FrameBuffer image to a PNG file. Note that in most cases
this will be a TIA image, but it could actually be used for *any* mode.
@param filename The filename to save the PNG image
@param framebuffer The framebuffer containing the image data
@param props The properties object containing info about the ROM
@param filename The filename to save the PNG image
@param props The properties object containing info about the ROM
@return On success, the PNG file has been saved to 'filename',
otherwise a const char* exception is thrown containing a
more detailed error message.
*/
string saveImage(const string& filename, const FrameBuffer& framebuffer,
const Properties& props);
void saveImage(const string& filename, const Properties& props);
/**
Save the current TIA image to a PNG file using data directly from
the TIA framebuffer. No filtering or scaling will be included.
the internal TIA buffer. No filtering or scaling will be included.
@param filename The filename to save the PNG image
@param framebuffer The framebuffer containing the image data
@param mediasrc Source of the raw TIA data
@param props The properties object containing info about the ROM
@param filename The filename to save the PNG image
@param tia Source of the raw TIA data
@param props The properties object containing info about the ROM
@return On success, the PNG file has been saved to 'filename',
otherwise a const char* exception is thrown containing a
more detailed error message.
*/
string saveImage(const string& filename, const FrameBuffer& framebuffer,
const TIA& tia, const Properties& props);
void saveImage(const string& filename, const TIA& tia, const Properties& props);
private:
const FrameBuffer& myFB;
// The following data remains between invocations of allocateStorage,
// and is only changed when absolutely necessary.
typedef struct {
@ -100,6 +105,9 @@ class PNGLibrary
The method fills the 'ReadInfo' struct with valid memory locations
dependent on the given dimensions. If memory has been previously
allocated and it can accommodate the given dimensions, it is used directly.
@param iwidth The width of the PNG image
@param iheight The height of the PNG image
*/
bool allocateStorage(png_uint_32 iwidth, png_uint_32 iheight);
@ -107,18 +115,17 @@ class PNGLibrary
Scale the PNG data from 'ReadInfo' into the FBSurface. For now, scaling
is done on integer boundaries only (ie, 1x, 2x, etc up or down).
@param fb The main framebuffer of the application
@param surface The FBSurface into which to place the PNG data
@param surface The FBSurface into which to place the PNG data
*/
void scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface);
void scaleImagetoSurface(FBSurface& surface);
string saveBufferToPNG(ofstream& out, uInt8* buffer,
uInt32 width, uInt32 height,
const Properties& props,
const string& effectsInfo);
void writePNGChunk(ofstream& out, const char* type, uInt8* data, int size);
void writePNGText(ofstream& out, const string& key, const string& text);
/**
Write PNG tEXt chunks to the image.
*/
void writeComments(png_structp png_ptr, png_infop info_ptr,
const Properties& props);
/** PNG library callback functions */
static void png_read_data(png_structp ctx, png_bytep area, png_size_t size);
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size);
static void png_io_flush(png_structp ctx);

View File

@ -771,8 +771,7 @@ int PromptWidget::vprintf(const char *format, va_list argptr)
void PromptWidget::putchar(int c)
{
putcharIntern(c);
setDirty(); draw(); // FIXME - not nice to redraw the full console just for one char!
setDirty(); draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -153,7 +153,7 @@ void EventHandler::reset(State state)
// We wait a little while, since 'hold' events may be present, and we want
// time for the ROM to process them
if(state == S_EMULATE)
SDL_AddTimer(500, resetEventsCallback, (void*)this); //FIXSDL
SDL_AddTimer(500, resetEventsCallback, (void*)this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1907,26 +1907,39 @@ void EventHandler::takeSnapshot(uInt32 number)
// Now create a PNG snapshot
if(myOSystem.settings().getBool("ss1x"))
{
string msg =
myOSystem.png().saveImage(filename, myOSystem.frameBuffer(),
myOSystem.console().tia(),
myOSystem.console().properties());
string message = "Snapshot saved";
try
{
myOSystem.png().saveImage(filename, myOSystem.console().tia(),
myOSystem.console().properties());
}
catch(const char* msg)
{
message = msg;
}
if(showmessage)
myOSystem.frameBuffer().showMessage(msg);
myOSystem.frameBuffer().showMessage(message);
}
else
{
// Make sure we have a 'clean' image, with no onscreen messages
myOSystem.frameBuffer().enableMessages(false);
string msg =
myOSystem.png().saveImage(filename, myOSystem.frameBuffer(),
myOSystem.console().properties());
string message = "Snapshot saved";
try
{
myOSystem.png().saveImage(filename, myOSystem.console().properties());
}
catch(const char* msg)
{
message = msg;
}
// Re-enable old messages
myOSystem.frameBuffer().enableMessages(true);
if(showmessage)
myOSystem.frameBuffer().showMessage(msg);
myOSystem.frameBuffer().showMessage(message);
}
}

View File

@ -535,14 +535,6 @@ void FrameBuffer::refresh()
case EventHandler::S_PAUSE:
invalidate();
drawTIA();
#if 0 // FIXME: eliminate stuttering in TIA mode; do we really need this?
if(isDoubleBuffered())
{
postFrameUpdate();
invalidate();
drawTIA();
}
#endif
break;
case EventHandler::S_MENU:

View File

@ -352,15 +352,16 @@ class FrameBuffer
virtual bool isDoubleBuffered() const = 0;
/**
This method is called to get the specified scanline data from the
viewable FrameBuffer area. Note that this isn't the same as any
internal surfaces that may be in use; it should return the actual
data as it is currently seen onscreen.
This method is called to get the specified ARGB data from the viewable
FrameBuffer area. Note that this isn't the same as any internal
surfaces that may be in use; it should return the actual data as it
is currently seen onscreen.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
@param rect The bounding rectangle for the buffer
@param buffer The actual pixel data in ARGB8888 format
@param pitch The pitch (in bytes) for the pixel data
*/
virtual void scanline(uInt32 row, uInt8* data) const = 0;
virtual void readPixels(const GUI::Rect& rect, uInt8* buffer, uInt32 pitch) const = 0;
protected:
/**

View File

@ -219,7 +219,7 @@ bool OSystem::create()
Random::setSystem(this);
// Create PNG handler
myPNGLib = new PNGLibrary();
myPNGLib = new PNGLibrary(*myFrameBuffer);
// Create ZIP handler
myZipHandler = new ZipHandler();

View File

@ -99,7 +99,7 @@ void RomInfoWidget::parseProperties()
// Initialize to empty properties entry
mySurfaceErrorMsg = "";
mySurfaceIsValid = false;
mySurfaceIsValid = true;
myRomInfo.clear();
// Get a valid filename representing a snapshot file for this rom
@ -109,8 +109,7 @@ void RomInfoWidget::parseProperties()
// Read the PNG file
try
{
mySurfaceIsValid =
instance().png().loadImage(filename, instance().frameBuffer(), *mySurface);
instance().png().loadImage(filename, *mySurface);
}
catch(const char* msg)
{