mirror of https://github.com/stella-emu/stella.git
Reworked the PNG save code a little, making it more abstract and not
having to know about TIA, Properties, etc. Basically, it now saves a snapshot of either the FrameBuffer or an FBSurface, and adds text comments passed into it. The contents of the surface and comments are no longer calculated (or known) by the PNG code. This is in preparation for saving FBSurface from anywhere, which will help in the debugger for taking snapshots. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2928 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
2d32f3d39a
commit
78f5a2acef
|
@ -117,7 +117,7 @@ bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode,
|
|||
|
||||
uInt32 pos = myOSystem.settings().getBool("center")
|
||||
? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED;
|
||||
uInt32 flags = mode.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||
uInt32 flags = mode.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||
|
||||
// OSX seems to have issues with destroying the window, and wants to keep
|
||||
// the same handle
|
||||
|
@ -259,8 +259,8 @@ FBSurface* FrameBufferSDL2::createSurface(uInt32 w, uInt32 h,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL2::readPixels(const GUI::Rect& rect,
|
||||
uInt8* pixels, uInt32 pitch) const
|
||||
void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch,
|
||||
const GUI::Rect& rect) const
|
||||
{
|
||||
SDL_Rect r;
|
||||
r.x = rect.x(); r.y = rect.y();
|
||||
|
|
|
@ -96,16 +96,16 @@ class FrameBufferSDL2 : public FrameBuffer
|
|||
bool isDoubleBuffered() const { return myDblBufferedFlag; }
|
||||
|
||||
/**
|
||||
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.
|
||||
This method is called to get a copy of 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 rect The bounding rectangle for the buffer
|
||||
@param buffer The actual pixel data in ARGB8888 format
|
||||
@param buffer A copy of the pixel data in ARGB8888 format
|
||||
@param pitch The pitch (in bytes) for the pixel data
|
||||
@param rect The bounding rectangle for the buffer
|
||||
*/
|
||||
void readPixels(const GUI::Rect& rect, uInt8* buffer, uInt32 pitch) const;
|
||||
void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "FrameBuffer.hxx"
|
||||
#include "Props.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "Version.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -129,22 +128,67 @@ done:
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(const string& filename, const Properties& props)
|
||||
void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
|
||||
{
|
||||
ofstream out(filename.c_str(), ios_base::binary);
|
||||
if(!out.is_open())
|
||||
throw "ERROR: Couldn't create snapshot file";
|
||||
|
||||
const GUI::Rect& rect = myFB.imageRect();
|
||||
png_uint_32 width = rect.width(), height = rect.height();
|
||||
|
||||
// Get framebuffer pixel data (we get ABGR format)
|
||||
png_bytep buffer = new png_byte[width * height * 4];
|
||||
myFB.readPixels(buffer, width*4, rect);
|
||||
|
||||
// Set up pointers into "buffer" byte array
|
||||
png_bytep* rows = new png_bytep[height];
|
||||
for(png_uint_32 k = 0; k < height; ++k)
|
||||
rows[k] = (png_bytep) (buffer + k*width*4);
|
||||
|
||||
// And save the image
|
||||
saveImage(out, buffer, rows, width, height, comments);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(const string& filename, const FBSurface& surface,
|
||||
const GUI::Rect& rect, const VariantList& comments)
|
||||
{
|
||||
ofstream out(filename.c_str(), ios_base::binary);
|
||||
if(!out.is_open())
|
||||
throw "ERROR: Couldn't create snapshot file";
|
||||
|
||||
// Do we want the entire surface or just a section?
|
||||
png_uint_32 width = rect.width(), height = rect.height();
|
||||
if(rect.isEmpty())
|
||||
{
|
||||
width = surface.width();
|
||||
height = surface.height();
|
||||
}
|
||||
|
||||
// Get the surface pixel data (we get ABGR format)
|
||||
png_bytep buffer = new png_byte[width * height * 4];
|
||||
surface.readPixels(buffer, width, rect);
|
||||
|
||||
// Set up pointers into "buffer" byte array
|
||||
png_bytep* rows = new png_bytep[height];
|
||||
for(png_uint_32 k = 0; k < height; ++k)
|
||||
rows[k] = (png_bytep) (buffer + k*width*4);
|
||||
|
||||
// And save the image
|
||||
saveImage(out, buffer, rows, width, height, comments);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(ofstream& out, png_bytep& buffer, png_bytep*& rows,
|
||||
png_uint_32 width, png_uint_32 height, const VariantList& comments)
|
||||
{
|
||||
#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 = new png_bytep[height];
|
||||
|
||||
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);
|
||||
|
@ -165,7 +209,7 @@ void PNGLibrary::saveImage(const string& filename, const Properties& props)
|
|||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
// Write comments
|
||||
writeComments(png_ptr, info_ptr, props);
|
||||
writeComments(png_ptr, info_ptr, comments);
|
||||
|
||||
// Write the file header information. REQUIRED
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
@ -182,15 +226,8 @@ void PNGLibrary::saveImage(const string& filename, const Properties& props)
|
|||
// 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] = (png_bytep) (image + k*width*4);
|
||||
|
||||
// Write the entire image in one go
|
||||
png_write_image(png_ptr, row_pointers);
|
||||
png_write_image(png_ptr, rows);
|
||||
|
||||
// We're finished writing
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
@ -199,94 +236,14 @@ void PNGLibrary::saveImage(const string& filename, const Properties& props)
|
|||
done:
|
||||
if(png_ptr)
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
if(image)
|
||||
delete[] image;
|
||||
if (row_pointers)
|
||||
delete[] row_pointers;
|
||||
if(buffer)
|
||||
delete[] buffer;
|
||||
if (rows)
|
||||
delete[] rows;
|
||||
if(err_message)
|
||||
throw err_message;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::saveImage(const string& filename, const TIA& tia,
|
||||
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;
|
||||
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 = new png_bytep[height];
|
||||
uInt8 r, g, b;
|
||||
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)
|
||||
{
|
||||
for(uInt32 x = 0; x < tiaw; ++x)
|
||||
{
|
||||
uInt32 pixel = myFB.tiaSurface().pixel(y*tiaw+x);
|
||||
myFB.getRGB(pixel, &r, &g, &b);
|
||||
*buf_ptr++ = r;
|
||||
*buf_ptr++ = g;
|
||||
*buf_ptr++ = b;
|
||||
*buf_ptr++ = r;
|
||||
*buf_ptr++ = g;
|
||||
*buf_ptr++ = b;
|
||||
}
|
||||
// Set up pointers into "image" byte array
|
||||
buf_ptr = row_pointers[y] = image + y*width*3;
|
||||
}
|
||||
|
||||
// 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 (row_pointers)
|
||||
delete[] row_pointers;
|
||||
if (err_message)
|
||||
throw err_message;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h)
|
||||
{
|
||||
|
@ -382,29 +339,21 @@ void PNGLibrary::scaleImagetoSurface(FBSurface& surface)
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PNGLibrary::writeComments(png_structp png_ptr, png_infop info_ptr,
|
||||
const Properties& props)
|
||||
const VariantList& comments)
|
||||
{
|
||||
// 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;
|
||||
uInt32 numComments = comments.size();
|
||||
if(numComments == 0)
|
||||
return;
|
||||
|
||||
ostringstream version;
|
||||
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
||||
<< BSPF_ARCH << "]";
|
||||
|
||||
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());
|
||||
|
||||
png_set_text(png_ptr, info_ptr, text_ptr, 4);
|
||||
png_text text_ptr[numComments];
|
||||
for(uInt32 i = 0; i < numComments; ++i)
|
||||
{
|
||||
text_ptr[i].key = (char*) comments[i].first.c_str();
|
||||
text_ptr[i].text = (char*) comments[i].second.toString().c_str();
|
||||
text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text_ptr[i].text_length = 0;
|
||||
}
|
||||
png_set_text(png_ptr, info_ptr, text_ptr, numComments);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -61,27 +61,30 @@ class PNGLibrary
|
|||
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 props The properties object containing info about the ROM
|
||||
@param comments The text comments to add to the PNG image
|
||||
|
||||
@return On success, the PNG file has been saved to 'filename',
|
||||
otherwise a const char* exception is thrown containing a
|
||||
more detailed error message.
|
||||
*/
|
||||
void saveImage(const string& filename, const Properties& props);
|
||||
void saveImage(const string& filename,
|
||||
const VariantList& comments = EmptyVarList);
|
||||
|
||||
/**
|
||||
Save the current TIA image to a PNG file using data directly from
|
||||
the internal TIA buffer. No filtering or scaling will be included.
|
||||
Save the given surface to a PNG file.
|
||||
|
||||
@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
|
||||
@param filename The filename to save the PNG image
|
||||
@param surface The surface data for the PNG image
|
||||
@param rect The area of the surface to use
|
||||
@param comments The text comments to add to the PNG image
|
||||
|
||||
@return On success, the PNG file has been saved to 'filename',
|
||||
otherwise a const char* exception is thrown containing a
|
||||
more detailed error message.
|
||||
*/
|
||||
void saveImage(const string& filename, const TIA& tia, const Properties& props);
|
||||
void saveImage(const string& filename, const FBSurface& surface,
|
||||
const GUI::Rect& rect = GUI::EmptyRect,
|
||||
const VariantList& comments = EmptyVarList);
|
||||
|
||||
private:
|
||||
const FrameBuffer& myFB;
|
||||
|
@ -111,6 +114,19 @@ class PNGLibrary
|
|||
*/
|
||||
bool allocateStorage(png_uint_32 iwidth, png_uint_32 iheight);
|
||||
|
||||
/** The actual method which saves a PNG image.
|
||||
|
||||
@param out The output stream for writing PNG data
|
||||
@param buffer Actual PNG RGB data
|
||||
@param rows Pointer into 'buffer' for each row
|
||||
@param width The width of the PNG image
|
||||
@param height The height of the PNG image
|
||||
@param comments The text comments to add to the PNG image
|
||||
*/
|
||||
void saveImage(ofstream& out, png_bytep& buffer, png_bytep*& rows,
|
||||
png_uint_32 width, png_uint_32 height,
|
||||
const VariantList& comments);
|
||||
|
||||
/**
|
||||
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).
|
||||
|
@ -123,7 +139,7 @@ class PNGLibrary
|
|||
Write PNG tEXt chunks to the image.
|
||||
*/
|
||||
void writeComments(png_structp png_ptr, png_infop info_ptr,
|
||||
const Properties& props);
|
||||
const VariantList& comments);
|
||||
|
||||
/** PNG library callback functions */
|
||||
static void png_read_data(png_structp ctx, png_bytep area, png_size_t size);
|
||||
|
|
|
@ -82,6 +82,8 @@ static const Variant EmptyVariant("");
|
|||
class VariantList : public Common::Array< pair<string,Variant> >
|
||||
{
|
||||
public:
|
||||
VariantList() { }
|
||||
|
||||
void push_back(const Variant& name, const Variant& tag = EmptyVariant)
|
||||
{
|
||||
ensureCapacity(_size + 1);
|
||||
|
@ -89,4 +91,7 @@ class VariantList : public Common::Array< pair<string,Variant> >
|
|||
}
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static const VariantList EmptyVarList;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "StateManager.hxx"
|
||||
#include "M6532.hxx"
|
||||
#include "MouseControl.hxx"
|
||||
#include "Version.hxx"
|
||||
|
||||
#include "EventHandler.hxx"
|
||||
|
||||
|
@ -1904,20 +1905,30 @@ void EventHandler::takeSnapshot(uInt32 number)
|
|||
else
|
||||
filename = sspath + ".png";
|
||||
|
||||
// Some text fields to add to the PNG snapshot
|
||||
VariantList comments;
|
||||
ostringstream version;
|
||||
version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") ["
|
||||
<< BSPF_ARCH << "]";
|
||||
comments.push_back("Software", version.str());
|
||||
comments.push_back("ROM Name", myOSystem.console().properties().get(Cartridge_Name));
|
||||
comments.push_back("ROM MD5", myOSystem.console().properties().get(Cartridge_MD5));
|
||||
comments.push_back("TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
|
||||
|
||||
// Now create a PNG snapshot
|
||||
if(myOSystem.settings().getBool("ss1x"))
|
||||
{
|
||||
string message = "Snapshot saved";
|
||||
try
|
||||
{
|
||||
myOSystem.png().saveImage(filename, myOSystem.console().tia(),
|
||||
myOSystem.console().properties());
|
||||
GUI::Rect rect;
|
||||
const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect);
|
||||
myOSystem.png().saveImage(filename, surface, rect, comments);
|
||||
}
|
||||
catch(const char* msg)
|
||||
{
|
||||
message = msg;
|
||||
}
|
||||
|
||||
if(showmessage)
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
}
|
||||
|
@ -1929,7 +1940,7 @@ void EventHandler::takeSnapshot(uInt32 number)
|
|||
string message = "Snapshot saved";
|
||||
try
|
||||
{
|
||||
myOSystem.png().saveImage(filename, myOSystem.console().properties());
|
||||
myOSystem.png().saveImage(filename, comments);
|
||||
}
|
||||
catch(const char* msg)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,29 @@ FBSurface::FBSurface()
|
|||
myAttributes.blendalpha = 100;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurface::readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const
|
||||
{
|
||||
uInt8* src = (uInt8*) myPixels + rect.y() * myPitch + rect.x();
|
||||
|
||||
if(rect.isEmpty())
|
||||
memcpy(buffer, src, width() * height() * 4);
|
||||
else
|
||||
{
|
||||
uInt32 w = BSPF_min(rect.width(), width());
|
||||
uInt32 h = BSPF_min(rect.height(), height());
|
||||
|
||||
// Copy 'height' lines of width 'pitch' (in bytes for both)
|
||||
uInt8* dst = buffer;
|
||||
while(h--)
|
||||
{
|
||||
memcpy(dst, src, w * 4);
|
||||
src += myPitch * 4;
|
||||
dst += pitch * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FBSurface::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color)
|
||||
{
|
||||
|
|
|
@ -71,12 +71,22 @@ class FBSurface
|
|||
This method returns the surface pixel pointer and pitch, which are
|
||||
used when one wishes to modify the surface pixels directly.
|
||||
*/
|
||||
inline void basePtr(uInt32*& pixels, uInt32& pitch)
|
||||
inline void basePtr(uInt32*& pixels, uInt32& pitch) const
|
||||
{
|
||||
pixels = myPixels;
|
||||
pitch = myPitch;
|
||||
}
|
||||
|
||||
/**
|
||||
This method is called to get a copy of the specified ARGB data from
|
||||
the behind-the-scenes surface.
|
||||
|
||||
@param buffer A copy of the pixel data in ARGB8888 format
|
||||
@param pitch The pitch (in bytes) for the pixel data
|
||||
@param rect The bounding rectangle for the buffer
|
||||
*/
|
||||
void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Note: The drawing primitives below will work, but do not take
|
||||
// advantage of any acceleration whatsoever. The methods are
|
||||
|
|
|
@ -160,7 +160,7 @@ bool FrameBuffer::initialize()
|
|||
FBSurface::setPalette(myPalette);
|
||||
|
||||
// Create a TIA surface; we need it for rendering TIA images
|
||||
myTIASurface = new TIASurface(*this, myOSystem);
|
||||
myTIASurface = new TIASurface(myOSystem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -357,11 +357,11 @@ class FrameBuffer
|
|||
surfaces that may be in use; it should return the actual data as it
|
||||
is currently seen onscreen.
|
||||
|
||||
@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
|
||||
@param rect The bounding rectangle for the buffer
|
||||
*/
|
||||
virtual void readPixels(const GUI::Rect& rect, uInt8* buffer, uInt32 pitch) const = 0;
|
||||
virtual void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
|
@ -26,12 +26,13 @@
|
|||
#include "TIASurface.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TIASurface::TIASurface(FrameBuffer& buffer, OSystem& system)
|
||||
: myFB(buffer),
|
||||
myOSystem(system),
|
||||
TIASurface::TIASurface(OSystem& system)
|
||||
: myOSystem(system),
|
||||
myFB(system.frameBuffer()),
|
||||
myTIA(NULL),
|
||||
myTiaSurface(NULL),
|
||||
mySLineSurface(NULL),
|
||||
myBaseTiaSurface(NULL),
|
||||
myFilterType(kNormal),
|
||||
myUsePhosphor(false),
|
||||
myPhosphorBlend(77),
|
||||
|
@ -53,6 +54,10 @@ TIASurface::TIASurface(FrameBuffer& buffer, OSystem& system)
|
|||
}
|
||||
uInt32 scanID = myFB.allocateSurface(1, kScanH, scanData);
|
||||
mySLineSurface = myFB.surface(scanID);
|
||||
|
||||
// Base TIA surface for use in taking snapshots in 1x mode
|
||||
uInt32 baseID = myFB.allocateSurface(kTIAW*2, kTIAH);
|
||||
myBaseTiaSurface = myFB.surface(baseID);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -125,6 +130,30 @@ void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette
|
|||
myNTSCFilter.setTIAPalette(*this, rgb_palette);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const FBSurface& TIASurface::baseSurface(GUI::Rect& rect)
|
||||
{
|
||||
uInt32 tiaw = myTIA->width(), width = tiaw*2, height = myTIA->height();
|
||||
rect.setBounds(0, 0, width, height);
|
||||
|
||||
// Fill the surface with pixels from the TIA, scaled 2x horizontally
|
||||
uInt32 *buffer, pitch;
|
||||
myBaseTiaSurface->basePtr(buffer, pitch);
|
||||
uInt32* buf_ptr = buffer;
|
||||
|
||||
for(uInt32 y = 0; y < height; ++y)
|
||||
{
|
||||
for(uInt32 x = 0; x < tiaw; ++x)
|
||||
{
|
||||
uInt32 pixel = myFB.tiaSurface().pixel(y*tiaw+x);
|
||||
*buf_ptr++ = pixel;
|
||||
*buf_ptr++ = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
return *myBaseTiaSurface;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift) const
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ class FrameBuffer;
|
|||
class FBSurface;
|
||||
class VideoMode;
|
||||
|
||||
#include "Rect.hxx"
|
||||
#include "NTSCFilter.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
|
@ -47,7 +48,7 @@ class TIASurface
|
|||
/**
|
||||
Creates a new TIASurface object
|
||||
*/
|
||||
TIASurface(FrameBuffer& buffer, OSystem& system);
|
||||
TIASurface(OSystem& system);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
|
@ -72,6 +73,11 @@ class TIASurface
|
|||
*/
|
||||
void setPalette(const uInt32* tia_palette, const uInt32* rgb_palette);
|
||||
|
||||
/**
|
||||
Get the TIA base surface for use in saving to a PNG image.
|
||||
*/
|
||||
const FBSurface& baseSurface(GUI::Rect& rect);
|
||||
|
||||
/**
|
||||
Get the TIA pixel associated with the given TIA buffer index,
|
||||
shifting by the given offset (for greyscale values).
|
||||
|
@ -136,11 +142,11 @@ class TIASurface
|
|||
void render();
|
||||
|
||||
private:
|
||||
FrameBuffer& myFB;
|
||||
OSystem& myOSystem;
|
||||
FrameBuffer& myFB;
|
||||
TIA* myTIA;
|
||||
|
||||
FBSurface *myTiaSurface, *mySLineSurface;
|
||||
FBSurface *myTiaSurface, *mySLineSurface, *myBaseTiaSurface;
|
||||
|
||||
// Enumeration created such that phosphor off/on is in LSB,
|
||||
// and Blargg off/on is in MSB
|
||||
|
|
|
@ -159,6 +159,9 @@ struct Rect
|
|||
}
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static const Rect EmptyRect;
|
||||
|
||||
} // End of namespace GUI
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue