I FINALLY have Snapshot support working. The same snapshot code can

now be used in the X11 and SDL versions, and in the DOS and Win32
versions if someone wants to add support for it.  The only requirement
is the PNG library.  This is because the snapshot is now taken from the
'MediaSource' framebuffer, which is common to all versions.

Changed SDL to take advantage of the common snapshot code.

The X11 version no longer requires Imlib for snapshot support, as it now
uses the common snapshot code.

Removed (and buried) the SnapSDL code for good :)


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@45 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2002-03-10 01:29:55 +00:00
parent 6e1e8f3870
commit 3c3bc5b9b3
6 changed files with 228 additions and 262 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: makefile,v 1.9 2002-03-05 22:39:47 stephena Exp $
## $Id: makefile,v 1.10 2002-03-10 01:29:54 stephena Exp $
##============================================================================
##============================================================================
@ -53,9 +53,9 @@ OPTIMIZATIONS =
# LINUX_JOYSTICK = 1
### to include support for saving snapshots in png format
### (X version requires Imlib, SDL version requires libpng)
# X11_SNAPSHOT = 1
# SDL_SNAPSHOT = 1
### (requires PNG library)
### Only X11 and SDL ports supported for now
# SNAPSHOT_SUPPORT = 1
##============================================================================
## All done, type make to get a list of frontends
@ -68,6 +68,7 @@ LD = g++
LDFLAGS =
LDLIBS =
OBJS.X11 =
OPTS.X11 =
LIBS.X11 =
CFLAGS.X11 =
@ -109,15 +110,13 @@ ifdef LINUX_JOYSTICK
OPTS.X11 += -DLINUX_JOYSTICK
endif
ifdef X11_SNAPSHOT
OPTS.X11 += -DHAVE_IMLIB
LIBS.X11 += `imlib-config --libs`
CFLAGS.X11 += `imlib-config --cflags`
endif
ifdef SNAPSHOT_SUPPORT
OBJS.X11 += Snapshot.o
OPTS.X11 += -DHAVE_PNG -I$(UI)/common
LIBS.X11 += -lpng
ifdef SDL_SNAPSHOT
OBJS.SDL += SnapSDL.o
OPTS.SDL += -DHAVE_PNG
OBJS.SDL += Snapshot.o
OPTS.SDL += -DHAVE_PNG -I$(UI)/common
LIBS.SDL += -lpng
endif
@ -171,7 +170,8 @@ linux-x:
LDFLAGS+="$(CFLAGS.X11)" \
LDLIBS="-lX11 -lXext" \
LDLIBS+="$(LIBS.X11)" \
OBJS="mainX11.o SndUnix.o"
OBJS="mainX11.o SndUnix.o" \
OBJS+="$(OBJS.X11)"
linux-sdl:
make stella.sdl \
@ -390,12 +390,12 @@ mainX11.o: $(UI)/x11/mainX11.cxx
mainSDL.o: $(UI)/sdl/mainSDL.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/mainSDL.cxx
SnapSDL.o: $(UI)/sdl/SnapSDL.cxx $(UI)/sdl/SnapSDL.hxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/SnapSDL.cxx
RectList.o: $(UI)/sdl/RectList.cxx $(UI)/sdl/RectList.hxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/sdl/RectList.cxx
Snapshot.o: $(UI)/common/Snapshot.cxx $(UI)/common/Snapshot.hxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(LDFLAGS) $(UI)/common/Snapshot.cxx
SndUnix.o: $(UI)/sound/SndUnix.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/sound/SndUnix.cxx

View File

@ -0,0 +1,178 @@
//============================================================================
//
// 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-1999 by Bradford W. Mott
//
// 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 2002-03-10 01:29:54 stephena Exp $
//============================================================================
#include <png.h>
#include <iostream>
#include <fstream>
#include "Snapshot.hxx"
Snapshot::Snapshot()
{
palette = (png_colorp) NULL;
}
Snapshot::~Snapshot()
{
if(palette)
delete[] palette;
}
void Snapshot::png_write_data(png_structp ctx, png_bytep area, png_size_t size)
{
ofstream* out = (ofstream *) png_get_io_ptr(ctx);
out->write(area, size);
}
void Snapshot::png_io_flush(png_structp ctx)
{
ofstream* out = (ofstream *) png_get_io_ptr(ctx);
out->flush();
}
void Snapshot::png_user_warn(png_structp ctx, png_const_charp str)
{
cerr << "Snapshot: libpng warning: " << str << endl;
}
void Snapshot::png_user_error(png_structp ctx, png_const_charp str)
{
cerr << "Snapshot: libpng error: " << str << endl;
}
/**
This routine saves the current frame buffer to a 256 color PNG file,
appropriately scaled by the amount specified in 'multiplier'.
*/
int Snapshot::savePNG(string filename, MediaSource& mediaSource, int multiplier)
{
png_structp png_ptr = 0;
png_infop info_ptr = 0;
uInt8* pixels = mediaSource.currentFrameBuffer();
// PNG and window dimensions will be different because of scaling
int picWidth = mediaSource.width() * 2 * multiplier;
int picHeight = mediaSource.height() * multiplier;
int width = mediaSource.width();
int height = mediaSource.height();
ofstream* out = new ofstream(filename.c_str());
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 = mediaSource.palette();
for(uInt32 i = 0; i < 256; i += 2)
{
uInt8 r, g, b;
r = (uInt8) ((gamePalette[i] & 0x00ff0000) >> 16);
g = (uInt8) ((gamePalette[i] & 0x0000ff00) >> 8);
b = (uInt8) (gamePalette[i] & 0x000000ff);
palette[i].red = palette[i+1].red = r;
palette[i].green = palette[i+1].green = g;
palette[i].blue = palette[i+1].blue = b;
}
}
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;
}
// 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;
}
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);
// Write the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
// 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.
int scaleX = 2 * multiplier;
int scaleY = multiplier;
// Create a buffer to hold the new scanline.
uInt8* newScanline = new uInt8[width * scaleX];
uInt8* oldScanline;
// Look at each original scanline
for(int y = 0; y < height; y++)
{
// First construct a new scanline that is scaled
oldScanline = (uInt8*) pixels + y*width;
int px = 0;
for(int x = 0; x < width; x++)
for(int offx = 0; offx < scaleX; offx++)
newScanline[px++] = oldScanline[x];
// Now output the new scanline 'scaleY' times
for(int offy = 0; offy < scaleY; offy++)
{
png_bytep row_pointer = (uInt8*) newScanline;
png_write_row(png_ptr, row_pointer);
}
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
if(newScanline)
delete[] newScanline;
out->close();
return 1;
}

View File

@ -13,24 +13,24 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SnapSDL.hxx,v 1.2 2002-03-05 22:39:47 stephena Exp $
// $Id: Snapshot.hxx,v 1.1 2002-03-10 01:29:54 stephena Exp $
//============================================================================
#ifndef SNAPSHOTSDL_HXX
#define SNAPSHOTSDL_HXX
#ifndef SNAPSHOT_HXX
#define SNAPSHOT_HXX
#include <SDL.h>
#include <png.h>
#include <string>
#include "MediaSrc.hxx"
class SnapshotSDL
class Snapshot
{
public:
SnapshotSDL();
~SnapshotSDL();
Snapshot();
~Snapshot();
int savePNG(SDL_Surface *surface, const char *file);
void setPalette(Uint32 *palette);
int savePNG(string filename, MediaSource& mediaSource, int multiplier = 1);
private:
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size);
@ -41,11 +41,8 @@ class SnapshotSDL
static void png_user_error(png_structp ctx, png_const_charp str);
int png_colortype_from_surface(SDL_Surface *surface);
int IMG_SavePNG_RW(SDL_Surface *surface, SDL_RWops *src);
Uint32 *palette;
// The PNG palette
png_colorp palette;
};
#endif

View File

@ -1,184 +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-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: SnapSDL.cxx,v 1.3 2002-03-05 22:39:47 stephena Exp $
//============================================================================
#include <SDL.h>
#include <png.h>
#include <stdlib.h>
#include <iostream>
#include "SnapSDL.hxx"
SnapshotSDL::SnapshotSDL()
{
palette = (Uint32*) NULL;
}
SnapshotSDL::~SnapshotSDL()
{
}
int SnapshotSDL::savePNG(SDL_Surface *surface, const char *file)
{
SDL_RWops *out = SDL_RWFromFile(file, "wb");
if(!out)
return 0;
int ret = IMG_SavePNG_RW(surface, out);
SDL_RWclose(out);
return ret;
}
/* Save a PNG type image to an SDL datasource */
void SnapshotSDL::png_write_data(png_structp ctx, png_bytep area, png_size_t size)
{
SDL_RWops *src;
src = (SDL_RWops *) png_get_io_ptr(ctx);
SDL_RWwrite(src, area, size, 1);
}
void SnapshotSDL::png_io_flush(png_structp ctx)
{
SDL_RWops *src;
src = (SDL_RWops *)png_get_io_ptr(ctx);
/* how do I flush src? */
}
int SnapshotSDL::png_colortype_from_surface(SDL_Surface *surface)
{
int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
if (surface->format->palette)
colortype |= PNG_COLOR_MASK_PALETTE;
else if (surface->format->Amask)
colortype |= PNG_COLOR_MASK_ALPHA;
return colortype;
}
void SnapshotSDL::png_user_warn(png_structp ctx, png_const_charp str)
{
cerr << "SnapshotSDL: libpng warning: " << str << endl;
}
void SnapshotSDL::png_user_error(png_structp ctx, png_const_charp str)
{
cerr << "SnapshotSDL: libpng error: " << str << endl;
}
int SnapshotSDL::IMG_SavePNG_RW(SDL_Surface *surface, SDL_RWops *src)
{
png_structp png_ptr = 0;
png_infop info_ptr = 0;
png_colorp palette = 0;
png_bytep *row_pointers = 0;
int i;
int colortype;
int result = 0;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_user_error, png_user_warn);
if(png_ptr == NULL)
{
cerr << "SnapshotSDL: Couldn't allocate memory for PNG file\n";
return 0;
}
/* Allocate/initialize the image information data. REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
{
cerr << "SnapshotSDL: Couldn't create image information for PNG file\n";
goto done;
}
png_set_write_fn(png_ptr, src, png_write_data, png_io_flush);
/* Set the image information here. Width and height are up to 2^31,
* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
* or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
*/
colortype = png_colortype_from_surface(surface);
png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8,
colortype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
/* set the palette if there is one. REQUIRED for indexed-color images */
if(colortype & PNG_COLOR_MASK_PALETTE)
{
palette = (png_colorp)malloc(surface->format->palette->ncolors * sizeof (png_color));
if(!palette)
{
cerr << "SnapshotSDL: Couldn't allocate memory for PNG palette\n";
goto done;
}
for(i = 0; i < surface->format->palette->ncolors; i++)
{
palette[i].red = surface->format->palette->colors[i].r;
palette[i].green = surface->format->palette->colors[i].g;
palette[i].blue = surface->format->palette->colors[i].b;
}
png_set_PLTE(png_ptr, info_ptr, palette, surface->format->palette->ncolors);
}
// Write the file header information. REQUIRED
png_write_info(png_ptr, info_ptr);
// pack pixels into bytes
png_set_packing(png_ptr);
// Create the array of pointers to image data
row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surface->h);
if((row_pointers == NULL))
{
cerr << "SnapshotSDL: Couldn't allocate PNG row pointers\n";
goto done;
}
for(i = 0; i < surface->h; i++)
row_pointers[i] = (png_bytep)(Uint8 *)surface->pixels + i*surface->pitch;
// write out the entire image data in one call
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
result = 1;
done:
if(row_pointers)
free(row_pointers);
if(info_ptr->palette)
free(info_ptr->palette);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return result;
}
void SnapshotSDL::setPalette(Uint32 *palette)
{
this->palette = palette;
}

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: mainSDL.cxx,v 1.11 2002-03-05 22:39:47 stephena Exp $
// $Id: mainSDL.cxx,v 1.12 2002-03-10 01:29:55 stephena Exp $
//============================================================================
#include <fstream>
@ -35,9 +35,12 @@
#include "PropsSet.hxx"
#include "System.hxx"
#include "SndUnix.hxx"
#include "SnapSDL.hxx"
#include "RectList.hxx"
#ifdef HAVE_PNG
#include "Snapshot.hxx"
#endif
// Hack for SDL < 1.2.0
#ifndef SDL_ENABLE
#define SDL_ENABLE 1
@ -91,7 +94,7 @@ static int sdlflags;
static RectList* rectList;
#ifdef HAVE_PNG
static SnapshotSDL* snapshot;
static Snapshot* snapshot;
#endif
struct Switches
@ -296,9 +299,8 @@ bool setupDisplay()
}
#ifdef HAVE_PNG
// Take care of the snapshot stuff. Must be done before the screen is
// created.
snapshot = new SnapshotSDL();
// Take care of the snapshot stuff.
snapshot = new Snapshot();
if(theSnapShotDir == "")
theSnapShotDir = getenv("HOME");
@ -441,12 +443,6 @@ void recalculate8BitPalette()
palette[i] = palette[i+1] = SDL_MapRGB(format, r, g, b);
}
#ifdef HAVE_PNG
// Make sure that snapshots use this new palette
if(snapshot)
snapshot->setPalette(palette);
#endif
}
@ -483,12 +479,6 @@ void setupPalette()
break;
}
}
#ifdef HAVE_PNG
// Make sure that snapshots use this new palette
if(snapshot)
snapshot->setPalette(palette);
#endif
}
@ -1174,7 +1164,7 @@ void takeSnapshot()
filename = filename + ".png";
// Now save the snapshot file
snapshot->savePNG(screen, filename.c_str());
snapshot->savePNG(filename, theConsole->mediaSource(), theWindowSize);
if(access(filename.c_str(), F_OK) == 0)
cerr << "Snapshot saved as " << filename << endl;

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: mainX11.cxx,v 1.11 2002-03-05 22:39:47 stephena Exp $
// $Id: mainX11.cxx,v 1.12 2002-03-10 01:29:55 stephena Exp $
//============================================================================
#include <fstream>
@ -40,10 +40,10 @@
#include "SndUnix.hxx"
#include "System.hxx"
#ifdef HAVE_IMLIB
#include <Imlib.h>
#ifdef HAVE_PNG
#include "Snapshot.hxx"
ImlibData* imlibData;
static Snapshot* snapshot;
// The path to save snapshot files
string theSnapShotDir = "";
@ -395,12 +395,10 @@ bool setupDisplay()
XSelectInput(theDisplay, theWindow, eventMask);
// If imlib snapshots are enabled, set up some imlib stuff
#ifdef HAVE_IMLIB
imlibData = Imlib_init(theDisplay);
#ifdef HAVE_PNG
// Take care of the snapshot stuff.
snapshot = new Snapshot();
// By default, snapshot dir is HOME and name is ROMNAME, assuming that
// they haven't been specified on the commandline
if(theSnapShotDir == "")
theSnapShotDir = getenv("HOME");
if(theSnapShotName == "")
@ -600,12 +598,6 @@ void handleEvents()
{
resizeWindow(0);
}
#if 0
else if((key == XK_F11) && (event.type == KeyPress))
{
toggleFullscreen();
}
#endif
else if((key == XK_F12) && (event.type == KeyPress))
{
takeSnapshot();
@ -1023,16 +1015,10 @@ bool createCursors()
*/
void takeSnapshot()
{
#ifdef HAVE_IMLIB
// Figure out the actual size of the window
int width = theWidth * 2 * theWindowSize;
int height = theHeight * theWindowSize;
ImlibImage* image = Imlib_create_image_from_drawable(imlibData, theWindow,
0, 0, 0, width, height);
if(image == NULL)
#ifdef HAVE_PNG
if(!snapshot)
{
cerr << "Could not create snapshot!!\n";
cerr << "Snapshot support disabled.\n";
return;
}
@ -1078,8 +1064,7 @@ void takeSnapshot()
filename = filename + ".png";
// Now save the snapshot file
Imlib_save_image(imlibData, image, (char*)filename.c_str(), NULL);
Imlib_kill_image(imlibData, image);
snapshot->savePNG(filename, theConsole->mediaSource(), theWindowSize);
if(access(filename.c_str(), F_OK) == 0)
cerr << "Snapshot saved as " << filename << endl;
@ -1148,7 +1133,7 @@ void usage()
" -paddle <0|1|2|3> Indicates which paddle the mouse should emulate",
#endif
" -showinfo Shows some game info on exit",
#ifdef HAVE_IMLIB
#ifdef HAVE_PNG
" -ssdir <path> The directory to save snapshot files to",
" -ssname <name> How to name the snapshot (romname or md5sum)",
" -sssingle Generate single snapshot instead of many",
@ -1299,7 +1284,7 @@ void handleCommandLineArguments(int argc, char* argv[])
theDesiredVolume = volume;
}
#ifdef HAVE_IMLIB
#ifdef HAVE_PNG
else if(string(argv[i]) == "-ssdir")
{
theSnapShotDir = argv[++i];
@ -1477,7 +1462,7 @@ void parseRCOptions(istream& in)
theDesiredVolume = volume;
}
#ifdef HAVE_IMLIB
#ifdef HAVE_PNG
else if(key == "ssdir")
{
theSnapShotDir = value;