mirror of https://github.com/stella-emu/stella.git
Reorganization of the PNG handling; it didn't make sense to have loading
one class and saving in another. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2588 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
266f6c47c1
commit
b0db10e969
|
@ -17,11 +17,17 @@
|
||||||
// $Id$
|
// $Id$
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "FrameBuffer.hxx"
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
#include "FrameBuffer.hxx"
|
||||||
|
#include "Props.hxx"
|
||||||
|
#include "TIA.hxx"
|
||||||
|
#include "Version.hxx"
|
||||||
#include "PNGLibrary.hxx"
|
#include "PNGLibrary.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -38,7 +44,7 @@ PNGLibrary::~PNGLibrary()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool PNGLibrary::readImage(const string& filename,
|
bool PNGLibrary::loadImage(const string& filename,
|
||||||
const FrameBuffer& fb, FBSurface& surface)
|
const FrameBuffer& fb, FBSurface& surface)
|
||||||
{
|
{
|
||||||
#define readImageERROR(s) { err_message = s; goto done; }
|
#define readImageERROR(s) { err_message = s; goto done; }
|
||||||
|
@ -125,6 +131,140 @@ done:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string PNGLibrary::saveImage(const string& filename,
|
||||||
|
const FrameBuffer& framebuffer,
|
||||||
|
const Properties& props)
|
||||||
|
{
|
||||||
|
ofstream out(filename.c_str(), ios_base::binary);
|
||||||
|
if(!out.is_open())
|
||||||
|
return "ERROR: Couldn't create snapshot 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];
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveBufferToPNG(out, buffer, width, height,
|
||||||
|
props, framebuffer.effectsInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string PNGLibrary::saveImage(const string& filename,
|
||||||
|
const FrameBuffer& framebuffer, 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";
|
||||||
|
|
||||||
|
uInt32 width = tia.width(), height = tia.height();
|
||||||
|
uInt8* buffer = new uInt8[(width*3*2 + 1) * height];
|
||||||
|
|
||||||
|
// Fill the buffer with pixels from the mediasrc
|
||||||
|
uInt8 r, g, b;
|
||||||
|
uInt8* buf_ptr = buffer;
|
||||||
|
for(uInt32 y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
*buf_ptr++ = 0; // first byte of row is filter type
|
||||||
|
for(uInt32 x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
uInt32 pixel = framebuffer.tiaPixel(y*width+x);
|
||||||
|
framebuffer.getRGB(pixel, &r, &g, &b);
|
||||||
|
*buf_ptr++ = r;
|
||||||
|
*buf_ptr++ = g;
|
||||||
|
*buf_ptr++ = b;
|
||||||
|
*buf_ptr++ = r;
|
||||||
|
*buf_ptr++ = g;
|
||||||
|
*buf_ptr++ = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveBufferToPNG(out, buffer, width << 1, height,
|
||||||
|
props, framebuffer.effectsInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string PNGLibrary::saveBufferToPNG(ofstream& out, uInt8* buffer,
|
||||||
|
uInt32 width, uInt32 height,
|
||||||
|
const Properties& props,
|
||||||
|
const string& effectsInfo)
|
||||||
|
{
|
||||||
|
uInt8* compmem = (uInt8*) NULL;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
|
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
|
||||||
{
|
{
|
||||||
|
@ -218,6 +358,53 @@ void PNGLibrary::scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void PNGLibrary::writePNGChunk(ofstream& out, const char* type,
|
||||||
|
uInt8* data, int size)
|
||||||
|
{
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
// Write the header
|
||||||
|
out.write((const char*)temp, 8);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size)
|
void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,10 @@
|
||||||
|
|
||||||
class FrameBuffer;
|
class FrameBuffer;
|
||||||
class FBSurface;
|
class FBSurface;
|
||||||
|
class Properties;
|
||||||
|
class TIA;
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,13 +41,13 @@ class PNGLibrary
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PNGLibrary();
|
PNGLibrary();
|
||||||
~PNGLibrary();
|
virtual ~PNGLibrary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read a PNG image from the specified file into a FBSurface structure,
|
Read a PNG image from the specified file into a FBSurface structure,
|
||||||
scaling the image to the surface bounds.
|
scaling the image to the surface bounds.
|
||||||
|
|
||||||
@param filename The filename to load from
|
@param filename The filename to load the PNG image
|
||||||
@param fb The main framebuffer of the application
|
@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
|
||||||
|
|
||||||
|
@ -52,7 +55,30 @@ class PNGLibrary
|
||||||
result of true, otherwise a const char* exception is thrown
|
result of true, otherwise a const char* exception is thrown
|
||||||
containing a more detailed error message.
|
containing a more detailed error message.
|
||||||
*/
|
*/
|
||||||
bool readImage(const string& filename, const FrameBuffer& fb, FBSurface& surface);
|
bool loadImage(const string& filename, const FrameBuffer& fb, FBSurface& surface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Save the current TIA image to a PNG file using data from the Framebuffer.
|
||||||
|
Any postprocessing/filtering will be included.
|
||||||
|
|
||||||
|
@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
|
||||||
|
*/
|
||||||
|
string saveImage(const string& filename, const FrameBuffer& framebuffer,
|
||||||
|
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.
|
||||||
|
|
||||||
|
@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
|
||||||
|
*/
|
||||||
|
string saveImage(const string& filename, const FrameBuffer& framebuffer,
|
||||||
|
const TIA& tia, const Properties& props);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The following data remains between invocations of allocateStorage,
|
// The following data remains between invocations of allocateStorage,
|
||||||
|
@ -86,6 +112,13 @@ class PNGLibrary
|
||||||
*/
|
*/
|
||||||
void scaleImagetoSurface(const FrameBuffer& fb, FBSurface& surface);
|
void scaleImagetoSurface(const FrameBuffer& fb, 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);
|
||||||
|
|
||||||
static void png_read_data(png_structp ctx, png_bytep area, png_size_t size);
|
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_write_data(png_structp ctx, png_bytep area, png_size_t size);
|
||||||
static void png_io_flush(png_structp ctx);
|
static void png_io_flush(png_structp ctx);
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// SSSS tt lll lll
|
|
||||||
// SS SS tt ll ll
|
|
||||||
// SS tttttt eeee ll ll aaaa
|
|
||||||
// SSSS tt ee ee ll ll aa
|
|
||||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
||||||
// SS SS tt ee ll ll aa aa
|
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
|
||||||
//
|
|
||||||
// Copyright (c) 1995-2013 by Bradford W. Mott, Stephen Anthony
|
|
||||||
// and the Stella Team
|
|
||||||
//
|
|
||||||
// See the file "License.txt" for information on usage and redistribution of
|
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
#include <zlib.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <cstring>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "bspf.hxx"
|
|
||||||
#include "FrameBuffer.hxx"
|
|
||||||
#include "Props.hxx"
|
|
||||||
#include "TIA.hxx"
|
|
||||||
#include "Version.hxx"
|
|
||||||
#include "Snapshot.hxx"
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Snapshot::savePNG(const FrameBuffer& framebuffer, const Properties& props,
|
|
||||||
const string& filename)
|
|
||||||
{
|
|
||||||
ofstream out(filename.c_str(), ios_base::binary);
|
|
||||||
if(!out.is_open())
|
|
||||||
return "ERROR: Couldn't create snapshot 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];
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
return saveBufferToPNG(out, buffer, width, height,
|
|
||||||
props, framebuffer.effectsInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Snapshot::savePNG(const FrameBuffer& framebuffer, const TIA& tia,
|
|
||||||
const Properties& props, const string& filename)
|
|
||||||
{
|
|
||||||
ofstream out(filename.c_str(), ios_base::binary);
|
|
||||||
if(!out.is_open())
|
|
||||||
return "ERROR: Couldn't create snapshot file";
|
|
||||||
|
|
||||||
uInt32 width = tia.width(), height = tia.height();
|
|
||||||
uInt8* buffer = new uInt8[(width*3*2 + 1) * height];
|
|
||||||
|
|
||||||
// Fill the buffer with pixels from the mediasrc
|
|
||||||
uInt8 r, g, b;
|
|
||||||
uInt8* buf_ptr = buffer;
|
|
||||||
for(uInt32 y = 0; y < height; ++y)
|
|
||||||
{
|
|
||||||
*buf_ptr++ = 0; // first byte of row is filter type
|
|
||||||
for(uInt32 x = 0; x < width; ++x)
|
|
||||||
{
|
|
||||||
uInt32 pixel = framebuffer.tiaPixel(y*width+x);
|
|
||||||
framebuffer.getRGB(pixel, &r, &g, &b);
|
|
||||||
*buf_ptr++ = r;
|
|
||||||
*buf_ptr++ = g;
|
|
||||||
*buf_ptr++ = b;
|
|
||||||
*buf_ptr++ = r;
|
|
||||||
*buf_ptr++ = g;
|
|
||||||
*buf_ptr++ = b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return saveBufferToPNG(out, buffer, width << 1, height,
|
|
||||||
props, framebuffer.effectsInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Snapshot::saveBufferToPNG(ofstream& out, uInt8* buffer,
|
|
||||||
uInt32 width, uInt32 height,
|
|
||||||
const Properties& props,
|
|
||||||
const string& effectsInfo)
|
|
||||||
{
|
|
||||||
uInt8* compmem = (uInt8*) NULL;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void Snapshot::writePNGChunk(ofstream& out, const char* type,
|
|
||||||
uInt8* data, int size)
|
|
||||||
{
|
|
||||||
// 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];
|
|
||||||
|
|
||||||
// Write the header
|
|
||||||
out.write((const char*)temp, 8);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 Snapshot::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;
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// SSSS tt lll lll
|
|
||||||
// SS SS tt ll ll
|
|
||||||
// SS tttttt eeee ll ll aaaa
|
|
||||||
// SSSS tt ee ee ll ll aa
|
|
||||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
||||||
// SS SS tt ee ll ll aa aa
|
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
|
||||||
//
|
|
||||||
// Copyright (c) 1995-2013 by Bradford W. Mott, Stephen Anthony
|
|
||||||
// and the Stella Team
|
|
||||||
//
|
|
||||||
// See the file "License.txt" for information on usage and redistribution of
|
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
#ifndef SNAPSHOT_HXX
|
|
||||||
#define SNAPSHOT_HXX
|
|
||||||
|
|
||||||
class Properties;
|
|
||||||
class FrameBuffer;
|
|
||||||
class TIA;
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include "bspf.hxx"
|
|
||||||
|
|
||||||
class Snapshot
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Save the current TIA image to a PNG file using data from the Framebuffer.
|
|
||||||
Any postprocessing/filtering will be included.
|
|
||||||
|
|
||||||
@param framebuffer The framebuffer containing the image data
|
|
||||||
@param props The properties object containing info about the ROM
|
|
||||||
@param filename The filename of the PNG file
|
|
||||||
*/
|
|
||||||
static string savePNG(const FrameBuffer& framebuffer, const Properties& props,
|
|
||||||
const string& filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Save the current TIA image to a PNG file using data directly from
|
|
||||||
the TIA framebuffer. No filtering or scaling will be included.
|
|
||||||
|
|
||||||
@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 of the PNG file
|
|
||||||
*/
|
|
||||||
static string savePNG(const FrameBuffer& framebuffer, const TIA& tia,
|
|
||||||
const Properties& props, const string& filename);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static string saveBufferToPNG(ofstream& out, uInt8* buffer,
|
|
||||||
uInt32 width, uInt32 height,
|
|
||||||
const Properties& props,
|
|
||||||
const string& effectsInfo);
|
|
||||||
static void writePNGChunk(ofstream& out, const char* type, uInt8* data, int size);
|
|
||||||
static void writePNGText(ofstream& out, const string& key, const string& text);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -9,8 +9,7 @@ MODULE_OBJS := \
|
||||||
src/common/FBSurfaceTIA.o \
|
src/common/FBSurfaceTIA.o \
|
||||||
src/common/PNGLibrary.o \
|
src/common/PNGLibrary.o \
|
||||||
src/common/MouseControl.o \
|
src/common/MouseControl.o \
|
||||||
src/common/RectList.o \
|
src/common/RectList.o
|
||||||
src/common/Snapshot.o
|
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
src/common
|
src/common
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "ListWidget.hxx"
|
#include "ListWidget.hxx"
|
||||||
#include "ScrollBarWidget.hxx"
|
#include "ScrollBarWidget.hxx"
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "Snapshot.hxx"
|
|
||||||
#include "Sound.hxx"
|
#include "Sound.hxx"
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
#include "M6532.hxx"
|
#include "M6532.hxx"
|
||||||
|
@ -1986,9 +1985,10 @@ void EventHandler::takeSnapshot(uInt32 number)
|
||||||
// Now create a PNG snapshot
|
// Now create a PNG snapshot
|
||||||
if(myOSystem->settings().getBool("ss1x"))
|
if(myOSystem->settings().getBool("ss1x"))
|
||||||
{
|
{
|
||||||
string msg = Snapshot::savePNG(myOSystem->frameBuffer(),
|
string msg =
|
||||||
myOSystem->console().tia(),
|
myOSystem->png().saveImage(filename, myOSystem->frameBuffer(),
|
||||||
myOSystem->console().properties(), filename);
|
myOSystem->console().tia(),
|
||||||
|
myOSystem->console().properties());
|
||||||
if(showmessage)
|
if(showmessage)
|
||||||
myOSystem->frameBuffer().showMessage(msg);
|
myOSystem->frameBuffer().showMessage(msg);
|
||||||
}
|
}
|
||||||
|
@ -1997,8 +1997,9 @@ void EventHandler::takeSnapshot(uInt32 number)
|
||||||
// Make sure we have a 'clean' image, with no onscreen messages
|
// Make sure we have a 'clean' image, with no onscreen messages
|
||||||
myOSystem->frameBuffer().enableMessages(false);
|
myOSystem->frameBuffer().enableMessages(false);
|
||||||
|
|
||||||
string msg = Snapshot::savePNG(myOSystem->frameBuffer(),
|
string msg =
|
||||||
myOSystem->console().properties(), filename);
|
myOSystem->png().saveImage(filename, myOSystem->frameBuffer(),
|
||||||
|
myOSystem->console().properties());
|
||||||
|
|
||||||
// Re-enable old messages
|
// Re-enable old messages
|
||||||
myOSystem->frameBuffer().enableMessages(true);
|
myOSystem->frameBuffer().enableMessages(true);
|
||||||
|
|
|
@ -90,6 +90,7 @@ OSystem::OSystem()
|
||||||
myDebugger(NULL),
|
myDebugger(NULL),
|
||||||
myCheatManager(NULL),
|
myCheatManager(NULL),
|
||||||
myStateManager(NULL),
|
myStateManager(NULL),
|
||||||
|
myPNGLib(NULL),
|
||||||
myQuitLoop(false),
|
myQuitLoop(false),
|
||||||
myRomFile(""),
|
myRomFile(""),
|
||||||
myRomMD5(""),
|
myRomMD5(""),
|
||||||
|
@ -196,6 +197,7 @@ OSystem::~OSystem()
|
||||||
delete myEventHandler;
|
delete myEventHandler;
|
||||||
|
|
||||||
delete mySerialPort;
|
delete mySerialPort;
|
||||||
|
delete myPNGLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -304,6 +306,9 @@ bool OSystem::create()
|
||||||
// Let the random class know about us; it needs access to getTicks()
|
// Let the random class know about us; it needs access to getTicks()
|
||||||
Random::setSystem(this);
|
Random::setSystem(this);
|
||||||
|
|
||||||
|
// Create PNG handler
|
||||||
|
myPNGLib = new PNGLibrary();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace GUI {
|
||||||
|
|
||||||
#include "Array.hxx"
|
#include "Array.hxx"
|
||||||
#include "FrameBuffer.hxx"
|
#include "FrameBuffer.hxx"
|
||||||
|
#include "PNGLibrary.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
struct Resolution {
|
struct Resolution {
|
||||||
|
@ -172,6 +173,13 @@ class OSystem
|
||||||
*/
|
*/
|
||||||
StateManager& state() const { return *myStateManager; }
|
StateManager& state() const { return *myStateManager; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the PNG handler of the system.
|
||||||
|
|
||||||
|
@return The PNGlib object
|
||||||
|
*/
|
||||||
|
PNGLibrary& png() const { return *myPNGLib; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method should be called to load the current settings from an rc file.
|
This method should be called to load the current settings from an rc file.
|
||||||
It first loads the settings from the config file, then informs subsystems
|
It first loads the settings from the config file, then informs subsystems
|
||||||
|
@ -557,6 +565,9 @@ class OSystem
|
||||||
// Pointer to the StateManager object
|
// Pointer to the StateManager object
|
||||||
StateManager* myStateManager;
|
StateManager* myStateManager;
|
||||||
|
|
||||||
|
// PNG object responsible for loading/saving PNG images
|
||||||
|
PNGLibrary* myPNGLib;
|
||||||
|
|
||||||
// The list of log messages
|
// The list of log messages
|
||||||
string myLogMessages;
|
string myLogMessages;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include "FrameBuffer.hxx"
|
#include "FrameBuffer.hxx"
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
#include "PNGLibrary.hxx"
|
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "Widget.hxx"
|
#include "Widget.hxx"
|
||||||
|
|
||||||
|
@ -116,7 +115,7 @@ void RomInfoWidget::parseProperties()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mySurfaceIsValid =
|
mySurfaceIsValid =
|
||||||
myPNGLib.readImage(filename, instance().frameBuffer(), *mySurface);
|
instance().png().loadImage(filename, instance().frameBuffer(), *mySurface);
|
||||||
}
|
}
|
||||||
catch(const char* msg)
|
catch(const char* msg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include "Widget.hxx"
|
#include "Widget.hxx"
|
||||||
#include "Command.hxx"
|
#include "Command.hxx"
|
||||||
#include "StringList.hxx"
|
#include "StringList.hxx"
|
||||||
#include "PNGLibrary.hxx"
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,9 +51,6 @@ class RomInfoWidget : public Widget
|
||||||
FBSurface* mySurface;
|
FBSurface* mySurface;
|
||||||
int mySurfaceID;
|
int mySurfaceID;
|
||||||
|
|
||||||
// PNG object responsible for actually loading the PNG image
|
|
||||||
PNGLibrary myPNGLib;
|
|
||||||
|
|
||||||
// How much to zoom the PNG image
|
// How much to zoom the PNG image
|
||||||
int myZoomLevel;
|
int myZoomLevel;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue