Added snapshot support for both software and OpenGL modes. Snapshots

are now created from the framebuffer() instead of directly from the
Mediasource.

Removed all snapshot-related code from the Console, since it didn't
really belong there.  A static snapshot object is now created each
time a snapshot is done (in the EventHandler).

These changes should make it easier for those ports (like MacOSX) that
have native PNG-saving support to not use *any* of the snapshot code
at all.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@275 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2004-06-20 23:30:48 +00:00
parent 44584196ab
commit 464972cc31
12 changed files with 170 additions and 164 deletions

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: FrameBufferGL.cxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: FrameBufferGL.cxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#include <SDL.h>
@ -352,6 +352,17 @@ void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c)
glEnd();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::scanline(uInt32 row, uInt8* data)
{
// Invert the row, since OpenGL rows start at the bottom
// of the framebuffer
row = winHeight() - row - 1;
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, row, winWidth(), 1, GL_RGB, GL_UNSIGNED_BYTE, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::createTextures()
{

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: FrameBufferGL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: FrameBufferGL.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GL_HXX
@ -34,7 +34,7 @@ class MediaSource;
This class implements an SDL OpenGL framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferGL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
@version $Id: FrameBufferGL.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
*/
class FrameBufferGL : public FrameBufferSDL
{
@ -74,6 +74,24 @@ class FrameBufferGL : public FrameBufferSDL
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b)
{ return SDL_MapRGB(myTexture->format, r, g, b); }
/**
This routine is called to get the width of the onscreen image.
*/
virtual uInt32 winWidth() { return (uInt32) (myWidth * theZoomLevel * theAspectRatio); }
/**
This routine is called to get the height of the onscreen image.
*/
virtual uInt32 winHeight() { return myHeight * theZoomLevel; }
/**
This routine is called to get the specified scanline data.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
*/
virtual void scanline(uInt32 row, uInt8* data);
//////////////////////////////////////////////////////////////////////
// The following methods are derived from FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////

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: FrameBufferSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: FrameBufferSDL.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SDL_HXX
@ -35,7 +35,7 @@
the core FrameBuffer.
@author Stephen Anthony
@version $Id: FrameBufferSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
@version $Id: FrameBufferSDL.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
*/
class FrameBufferSDL : public FrameBuffer
{
@ -50,7 +50,6 @@ class FrameBufferSDL : public FrameBuffer
*/
virtual ~FrameBufferSDL();
/**
Toggles between fullscreen and window mode. Grabmouse and hidecursor
activated when in fullscreen mode.

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: FrameBufferSoft.cxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: FrameBufferSoft.cxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#include <SDL.h>
@ -383,6 +383,56 @@ void FrameBufferSoft::drawChar(uInt32 xorig, uInt32 yorig, uInt32 c)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::scanline(uInt32 row, uInt8* data)
{
// Make sure no pixels are being modified
SDL_LockSurface(myScreen);
uInt32 bpp = myScreen->format->BytesPerPixel;
uInt8* start = (uInt8*) myScreen->pixels;
uInt32 yoffset = row * myScreen->pitch;
uInt32 pixel = 0;
uInt8 *p, r, g, b;
for(Int32 x = 0; x < myScreen->w; x++)
{
p = (Uint8*) (start + // Start at top of RAM
(yoffset) + // Go down 'row' lines
(x * bpp)); // Go in 'x' pixels
switch(bpp)
{
case 1:
pixel = *p;
break;
case 2:
pixel = *(Uint16*) p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
pixel = p[0] << 16 | p[1] << 8 | p[2];
else
pixel = p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
pixel = *(Uint32*) p;
break;
}
SDL_GetRGB(pixel, myScreen->format, &r, &g, &b);
data[x * 3 + 0] = r;
data[x * 3 + 1] = g;
data[x * 3 + 2] = b;
}
SDL_UnlockSurface(myScreen);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RectList::RectList(Uint32 size)
{

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: FrameBufferSoft.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: FrameBufferSoft.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_SOFT_HXX
@ -35,7 +35,7 @@ class RectList;
This class implements an SDL software framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferSoft.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
@version $Id: FrameBufferSoft.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
*/
class FrameBufferSoft : public FrameBufferSDL
{
@ -69,6 +69,24 @@ class FrameBufferSoft : public FrameBufferSDL
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b)
{ return SDL_MapRGB(myScreen->format, r, g, b); }
/**
This routine is called to get the width of the onscreen image.
*/
virtual uInt32 winWidth() { return myScreen->w; }
/**
This routine is called to get the height of the onscreen image.
*/
virtual uInt32 winHeight() { return myScreen->h; }
/**
This routine is called to get the specified scanline data.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
*/
virtual void scanline(uInt32 row, uInt8* data);
//////////////////////////////////////////////////////////////////////
// The following methods are derived from FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////

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: Snapshot.cxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: Snapshot.cxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#include <png.h>
@ -22,23 +22,18 @@
#include "bspf.hxx"
#include "FrameBuffer.hxx"
#include "Console.hxx"
#include "MediaSrc.hxx"
#include "FrameBufferSDL.hxx"
#include "Snapshot.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Snapshot::Snapshot(Console* console, MediaSource* mediasrc)
: myConsole(console),
myMediaSource(mediasrc),
palette((png_colorp) NULL)
Snapshot::Snapshot(FrameBuffer& framebuffer)
: myFrameBuffer(framebuffer)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Snapshot::~Snapshot()
{
if(palette)
delete[] palette;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -68,78 +63,39 @@ void Snapshot::png_user_error(png_structp ctx, png_const_charp str)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 Snapshot::savePNG(string filename, uInt32 multiplier)
string Snapshot::savePNG(string filename)
{
// FIXME - we shouldn't use the mediasource, but should instead use
// the framebuffer.
// Right now, the snapshot doesn't take into account any special effects
// that the framebuffer may be performing (aspect correction, OpenGL, etc)
// This will require framebuffer support for exporting its actual pixels,
// so it will have to wait ...
png_structp png_ptr = 0;
png_infop info_ptr = 0;
png_infop info_ptr = 0;
uInt8* pixels = myMediaSource->currentFrameBuffer();
// PNG and window dimensions will be different because of scaling
uInt32 picWidth = myMediaSource->width() * multiplier << 1;
uInt32 picHeight = myMediaSource->height() * multiplier;
uInt32 width = myMediaSource->width();
uInt32 height = myMediaSource->height();
// Get actual screen dimensions. which are not always the same
// as the framebuffer dimensions
uInt32 width = myFrameBuffer.winWidth();
uInt32 height = myFrameBuffer.winHeight();
ofstream* out = new ofstream(filename.c_str(), ios_base::binary);
if(!out)
return 0;
// Create the palette if it hasn't previously been set
if(!palette)
{
palette = (png_colorp) new png_color[256];
if(!palette)
{
cerr << "Snapshot: Couldn't allocate memory for PNG palette\n";
out->close();
return 0;
}
const uInt32* gamePalette = myMediaSource->palette();
for(uInt32 i = 0; i < 256; ++i)
{
palette[i].red = (uInt8) ((gamePalette[i] & 0x00ff0000) >> 16);
palette[i].green = (uInt8) ((gamePalette[i] & 0x0000ff00) >> 8);
palette[i].blue = (uInt8) (gamePalette[i] & 0x000000ff);
}
}
return "Couldn't create snapshot file";
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_user_error, png_user_warn);
if(png_ptr == NULL)
{
cerr << "Snapshot: Couldn't allocate memory for PNG file\n";
return 0;
}
return "Snapshot: Out of memory";
// Allocate/initialize the image information data. REQUIRED.
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
{
cerr << "Snapshot: Couldn't create image information for PNG file\n";
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
out->close();
return 0;
return "Snapshot: Error on create image info";
}
png_set_write_fn(png_ptr, out, png_write_data, png_io_flush);
png_set_IHDR(png_ptr, info_ptr, picWidth, picHeight, 8,
PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// Set the 8-bit palette
png_set_PLTE(png_ptr, info_ptr, palette, 256);
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 the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
@ -147,42 +103,23 @@ uInt32 Snapshot::savePNG(string filename, uInt32 multiplier)
// Pack pixels into bytes
png_set_packing(png_ptr);
// The width has to be scaled by 2 * multiplier. Each pixel must be
// present scaleX times. Each scanline must be present scaleY times.
uInt32 scaleX = multiplier << 1;
uInt32 scaleY = multiplier;
// Create space for one full scanline (3 bytes per pixel in RGB format)
uInt8* data = new uInt8[width * 3];
// Create a buffer to hold the new scanline.
uInt8* newScanline = new uInt8[width * scaleX];
uInt8* oldScanline;
// Look at each original scanline
for(uInt32 y = 0; y < height; y++)
// Write a new scanline to the PNG file
for(uInt32 row = 0; row < height; row++)
{
// First construct a new scanline that is scaled
oldScanline = (uInt8*) pixels + y*width;
uInt32 px = 0;
for(uInt32 x = 0; x < width; x++)
for(uInt32 offx = 0; offx < scaleX; offx++)
newScanline[px++] = oldScanline[x];
// Now output the new scanline 'scaleY' times
for(uInt32 offy = 0; offy < scaleY; offy++)
{
png_bytep row_pointer = (uInt8*) newScanline;
png_write_row(png_ptr, row_pointer);
}
myFrameBuffer.scanline(row, data);
png_write_row(png_ptr, (png_bytep) data);
}
// Cleanup
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if(newScanline)
delete[] newScanline;
delete[] data;
out->close();
delete out;
return 1;
return "Snapshot saved";
}

View File

@ -13,14 +13,13 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Snapshot.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
// $Id: Snapshot.hxx,v 1.2 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef SNAPSHOT_HXX
#define SNAPSHOT_HXX
class Console;
class MediaSource;
class FrameBuffer;
#include <png.h>
#include "bspf.hxx"
@ -31,10 +30,9 @@ class Snapshot
/**
Create a new shapshot class for taking snapshots in PNG format.
@param console The console
@param mediasrc The mediasource
@param framebuffer The SDL framebuffer containing the image data
*/
Snapshot(Console* console, MediaSource* mediasrc);
Snapshot(FrameBuffer& framebuffer);
/**
The destructor.
@ -42,15 +40,13 @@ class Snapshot
~Snapshot();
/**
This routine saves the current frame buffer to a PNG file,
appropriately scaled by the amount specified in 'multiplier'.
This routine saves the current frame buffer to a PNG file.
@param filename The filename of the PNG file
@param multiplier The amount that multiplication (zoom level)
@param filename The filename of the PNG file
@return The resulting error code
@string The resulting string to print to the framebuffer
*/
uInt32 savePNG(string filename, uInt32 multiplier = 1);
string savePNG(string filename);
private:
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size);
@ -62,14 +58,8 @@ class Snapshot
static void png_user_error(png_structp ctx, png_const_charp str);
private:
// The Console for the system
Console* myConsole;
// The Mediasource for the system
MediaSource* myMediaSource;
// The PNG palette
png_colorp palette;
// The Framebuffer for the system
FrameBuffer& myFrameBuffer;
};
#endif

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: Console.cxx,v 1.30 2004-06-13 16:51:15 stephena Exp $
// $Id: Console.cxx,v 1.31 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#include <assert.h>
@ -174,11 +174,6 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
// Initialize the sound interface.
mySound.init(this, myMediaSource, mySystem);
#ifdef SNAPSHOT_SUPPORT
// Create a snapshot object which will handle taking snapshots
mySnapshot = new Snapshot(this, myMediaSource);
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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: Console.hxx,v 1.19 2004-06-13 16:51:15 stephena Exp $
// $Id: Console.hxx,v 1.20 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef CONSOLE_HXX
@ -26,7 +26,6 @@ class EventHandler;
class MediaSource;
class PropertiesSet;
class Settings;
class Snapshot;
class Sound;
class Switches;
class System;
@ -41,7 +40,7 @@ class FrameBuffer;
This class represents the entire game console.
@author Bradford W. Mott
@version $Id: Console.hxx,v 1.19 2004-06-13 16:51:15 stephena Exp $
@version $Id: Console.hxx,v 1.20 2004-06-20 23:30:48 stephena Exp $
*/
class Console
{
@ -171,22 +170,6 @@ class Console
*/
static const Properties& defaultProperties();
#ifdef SNAPSHOT_SUPPORT
public:
// Pointer to the Snapshot object
Snapshot* mySnapshot;
/**
Get the snapshot object of the console
@return The snapshot object for this console
*/
Snapshot& snapshot() const
{
return *mySnapshot;
}
#endif
#ifdef DEVELOPER_SUPPORT
public:
/**

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: EventHandler.cxx,v 1.26 2004-06-13 04:57:17 bwmott Exp $
// $Id: EventHandler.cxx,v 1.27 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#include <algorithm>
@ -22,7 +22,6 @@
#include "Console.hxx"
#include "Event.hxx"
#include "EventHandler.hxx"
#include "MediaSrc.hxx"
#include "Settings.hxx"
#include "StellaEvent.hxx"
#include "System.hxx"
@ -432,11 +431,10 @@ void EventHandler::takeSnapshot()
else
filename = sspath + ".png";
// Now save the snapshot file
uInt32 multiplier = myConsole->settings().getInt("zoom");
myConsole->snapshot().savePNG(filename, multiplier);
myConsole->frameBuffer().showMessage("Snapshot saved");
// Now create a Snapshot object and save the PNG
Snapshot snapshot(myConsole->frameBuffer());
string result = snapshot.savePNG(filename);
myConsole->frameBuffer().showMessage(result);
#else
myConsole->frameBuffer().showMessage("Snapshots unsupported");
#endif

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: EventHandler.hxx,v 1.13 2003-11-24 14:51:06 stephena Exp $
// $Id: EventHandler.hxx,v 1.14 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef EVENTHANDLER_HXX
@ -24,7 +24,6 @@
#include "StellaEvent.hxx"
class Console;
class MediaSource;
/**
@ -41,7 +40,7 @@ class MediaSource;
mapping can take place.
@author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.13 2003-11-24 14:51:06 stephena Exp $
@version $Id: EventHandler.hxx,v 1.14 2004-06-20 23:30:48 stephena Exp $
*/
class EventHandler
{
@ -90,13 +89,6 @@ class EventHandler
*/
void sendEvent(Event::Type type, Int32 value);
/**
Set the mediasource.
@param mediaSource The mediasource
*/
void setMediaSource(MediaSource* mediaSource);
/**
Enable/disable remapping mode.
@ -146,9 +138,6 @@ class EventHandler
// Global Event object
Event* myEvent;
// Global mediasource object
MediaSource* myMediaSource;
// Indicates the current state to use for state loading/saving
uInt32 myCurrentState;

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: FrameBuffer.hxx,v 1.7 2003-11-24 14:51:06 stephena Exp $
// $Id: FrameBuffer.hxx,v 1.8 2004-06-20 23:30:48 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_HXX
@ -35,7 +35,7 @@ class Console;
can be changed.
@author Stephen Anthony
@version $Id: FrameBuffer.hxx,v 1.7 2003-11-24 14:51:06 stephena Exp $
@version $Id: FrameBuffer.hxx,v 1.8 2004-06-20 23:30:48 stephena Exp $
*/
class FrameBuffer
{
@ -193,6 +193,24 @@ class FrameBuffer
*/
virtual void pauseEvent(bool status) = 0;
/**
This routine is called to get the width of the onscreen image.
*/
virtual uInt32 winWidth() = 0;
/**
This routine is called to get the height of the onscreen image.
*/
virtual uInt32 winHeight() = 0;
/**
This routine is called to get the specified scanline data.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
*/
virtual void scanline(uInt32 row, uInt8* data) = 0;
protected:
// The Console for the system
Console* myConsole;