mirror of https://github.com/stella-emu/stella.git
More codebase cleanups.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@246 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
469f00eefc
commit
8b5bdd2340
|
@ -1,188 +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: Snapshot.cxx,v 1.9 2003-12-06 00:17:28 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <png.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "Snapshot.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Snapshot::Snapshot(Console* console, MediaSource* mediasrc)
|
||||
: myConsole(console),
|
||||
myMediaSource(mediasrc),
|
||||
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((const char *)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;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Snapshot::savePNG(string filename, uInt32 multiplier)
|
||||
{
|
||||
// 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;
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
uInt32 scaleX = multiplier << 1;
|
||||
uInt32 scaleY = multiplier;
|
||||
|
||||
// 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++)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
|
||||
if(newScanline)
|
||||
delete[] newScanline;
|
||||
|
||||
out->close();
|
||||
delete out;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,75 +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: Snapshot.hxx,v 1.5 2003-11-19 15:57:10 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SNAPSHOT_HXX
|
||||
#define SNAPSHOT_HXX
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
|
||||
#include <png.h>
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Snapshot
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new shapshot class for taking snapshots in PNG format.
|
||||
|
||||
@param console The console
|
||||
@param mediasrc The mediasource
|
||||
*/
|
||||
Snapshot(Console* console, MediaSource* mediasrc);
|
||||
|
||||
/**
|
||||
The destructor.
|
||||
*/
|
||||
~Snapshot();
|
||||
|
||||
/**
|
||||
This routine saves the current frame buffer to a PNG file,
|
||||
appropriately scaled by the amount specified in 'multiplier'.
|
||||
|
||||
@param filename The filename of the PNG file
|
||||
@param multiplier The amount that multiplication (zoom level)
|
||||
|
||||
@return The resulting error code
|
||||
*/
|
||||
uInt32 savePNG(string filename, uInt32 multiplier = 1);
|
||||
|
||||
private:
|
||||
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_user_warn(png_structp ctx, png_const_charp str);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,537 +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: FrameBufferGL.cxx,v 1.19 2004-04-27 00:50:52 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "FrameBufferGL.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferGL::FrameBufferGL()
|
||||
: myTexture(0),
|
||||
myFilterParam(GL_NEAREST)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferGL::~FrameBufferGL()
|
||||
{
|
||||
if(myTexture)
|
||||
SDL_FreeSurface(myTexture);
|
||||
|
||||
glDeleteTextures(1, &myTextureID);
|
||||
glDeleteTextures(256, myFontTextureID);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferGL::createScreen()
|
||||
{
|
||||
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, myRGB[0] );
|
||||
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, myRGB[1] );
|
||||
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, myRGB[2] );
|
||||
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, myRGB[3] );
|
||||
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
||||
|
||||
GLint viewportX = 0, viewportY = 0;
|
||||
uInt32 screenWidth = 0;
|
||||
uInt32 screenHeight = 0;
|
||||
|
||||
uInt32 imageWidth = (uInt32) (myWidth * theZoomLevel * theAspectRatio);
|
||||
uInt32 imageHeight = myHeight * theZoomLevel;
|
||||
|
||||
// Determine if we're in fullscreen or windowed mode
|
||||
// In fullscreen mode, we clip the SDL screen to known resolutions
|
||||
// In windowed mode, we use the actual image resolution for the SDL screen
|
||||
if(mySDLFlags & SDL_FULLSCREEN)
|
||||
{
|
||||
SDL_Rect rect = viewport(imageWidth, imageHeight);
|
||||
|
||||
viewportX = rect.x;
|
||||
viewportY = rect.y;
|
||||
screenWidth = rect.w - 1;
|
||||
screenHeight = rect.h - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
screenWidth = imageWidth;
|
||||
screenHeight = imageHeight;
|
||||
viewportX = viewportY = 0;
|
||||
}
|
||||
|
||||
myScreen = SDL_SetVideoMode(screenWidth, screenHeight, 0, mySDLFlags);
|
||||
if(myScreen == NULL)
|
||||
{
|
||||
cerr << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
|
||||
// Center the screen horizontally and vertically
|
||||
glViewport(viewportX, viewportY, imageWidth, imageHeight);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glOrtho(0.0, (GLdouble) imageWidth/(theZoomLevel * theAspectRatio),
|
||||
(GLdouble) imageHeight/theZoomLevel, 0.0, 0.0, 1.0);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
#ifdef TEXTURES_ARE_LOST
|
||||
createTextures();
|
||||
#endif
|
||||
|
||||
// Make sure any old parts of the screen are erased
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
theRedrawEntireFrameIndicator = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferGL::init()
|
||||
{
|
||||
// Get the desired width and height of the display
|
||||
myWidth = myMediaSource->width() << 1;
|
||||
myHeight = myMediaSource->height();
|
||||
|
||||
// Get the aspect ratio for the display
|
||||
// Since the display is already doubled horizontally, we half the
|
||||
// ratio that is provided
|
||||
theAspectRatio = myConsole->settings().getFloat("gl_aspect") / 2;
|
||||
if(theAspectRatio <= 0.0)
|
||||
theAspectRatio = 1.0;
|
||||
|
||||
// Now create the OpenGL SDL screen
|
||||
Uint32 initflags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
|
||||
if(SDL_Init(initflags) < 0)
|
||||
return false;
|
||||
|
||||
// Check which system we are running under
|
||||
x11Available = false;
|
||||
#if UNIX && (!__APPLE__)
|
||||
SDL_VERSION(&myWMInfo.version);
|
||||
if(SDL_GetWMInfo(&myWMInfo) > 0)
|
||||
if(myWMInfo.subsystem == SDL_SYSWM_X11)
|
||||
x11Available = true;
|
||||
#endif
|
||||
|
||||
// Get the maximum size of a window for THIS screen
|
||||
theMaxZoomLevel = maxWindowSizeForScreen();
|
||||
|
||||
// Check to see if window size will fit in the screen
|
||||
if((uInt32)myConsole->settings().getInt("zoom") > theMaxZoomLevel)
|
||||
theZoomLevel = theMaxZoomLevel;
|
||||
else
|
||||
theZoomLevel = myConsole->settings().getInt("zoom");
|
||||
|
||||
mySDLFlags = SDL_OPENGL;
|
||||
mySDLFlags |= myConsole->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
|
||||
|
||||
// Set the window title and icon
|
||||
setWindowAttributes();
|
||||
|
||||
// Set up the OpenGL attributes
|
||||
myDepth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
|
||||
switch(myDepth)
|
||||
{
|
||||
case 8:
|
||||
myRGB[0] = 3;
|
||||
myRGB[1] = 3;
|
||||
myRGB[2] = 2;
|
||||
myRGB[3] = 0;
|
||||
break;
|
||||
|
||||
case 15:
|
||||
myRGB[0] = 5;
|
||||
myRGB[1] = 5;
|
||||
myRGB[2] = 5;
|
||||
myRGB[3] = 0;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
myRGB[0] = 5;
|
||||
myRGB[1] = 6;
|
||||
myRGB[2] = 5;
|
||||
myRGB[3] = 0;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
myRGB[0] = 8;
|
||||
myRGB[1] = 8;
|
||||
myRGB[2] = 8;
|
||||
myRGB[3] = 0;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
myRGB[0] = 8;
|
||||
myRGB[1] = 8;
|
||||
myRGB[2] = 8;
|
||||
myRGB[3] = 8;
|
||||
break;
|
||||
|
||||
default: // This should never happen
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the screen
|
||||
if(!createScreen())
|
||||
return false;
|
||||
|
||||
// Now check to see what color components were actually created
|
||||
SDL_GL_GetAttribute( SDL_GL_RED_SIZE, (int*)&myRGB[0] );
|
||||
SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, (int*)&myRGB[1] );
|
||||
SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, (int*)&myRGB[2] );
|
||||
SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, (int*)&myRGB[3] );
|
||||
|
||||
#ifndef TEXTURES_ARE_LOST
|
||||
// Create the texture surface and texture fonts
|
||||
createTextures();
|
||||
#endif
|
||||
|
||||
// Set up the palette *after* we know the color components
|
||||
// and the textures
|
||||
setupPalette();
|
||||
|
||||
// Show some OpenGL info
|
||||
if(myConsole->settings().getBool("showinfo"))
|
||||
{
|
||||
ostringstream colormode;
|
||||
colormode << "Color : " << myDepth << " bit, " << myRGB[0] << "-"
|
||||
<< myRGB[1] << "-" << myRGB[2] << "-" << myRGB[3];
|
||||
|
||||
cout << endl
|
||||
<< "Vendor : " << glGetString(GL_VENDOR) << endl
|
||||
<< "Renderer: " << glGetString(GL_RENDERER) << endl
|
||||
<< "Version : " << glGetString(GL_VERSION) << endl
|
||||
<< colormode.str() << endl << endl;
|
||||
}
|
||||
|
||||
// Make sure that theUseFullScreenFlag sets up fullscreen mode correctly
|
||||
if(myConsole->settings().getBool("fullscreen"))
|
||||
{
|
||||
grabMouse(true);
|
||||
showCursor(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep mouse in game window if grabmouse is selected
|
||||
grabMouse(myConsole->settings().getBool("grabmouse"));
|
||||
|
||||
// Show or hide the cursor depending on the 'hidecursor' argument
|
||||
showCursor(!myConsole->settings().getBool("hidecursor"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawMediaSource()
|
||||
{
|
||||
// Copy the mediasource framebuffer to the RGB texture
|
||||
uInt8* currentFrame = myMediaSource->currentFrameBuffer();
|
||||
uInt8* previousFrame = myMediaSource->previousFrameBuffer();
|
||||
uInt32 width = myMediaSource->width();
|
||||
uInt32 height = myMediaSource->height();
|
||||
uInt16* buffer = (uInt16*) myTexture->pixels;
|
||||
|
||||
register uInt32 y;
|
||||
for(y = 0; y < height; ++y )
|
||||
{
|
||||
const uInt32 bufofsY = y * width;
|
||||
const uInt32 screenofsY = y * myTexture->w;
|
||||
|
||||
register uInt32 x;
|
||||
for(x = 0; x < width; ++x )
|
||||
{
|
||||
const uInt32 bufofs = bufofsY + x;
|
||||
uInt8 v = currentFrame[bufofs];
|
||||
if(v == previousFrame[bufofs] && !theRedrawEntireFrameIndicator)
|
||||
continue;
|
||||
|
||||
// x << 1 is times 2 ( doubling width )
|
||||
const uInt32 pos = screenofsY + (x << 1);
|
||||
buffer[pos] = buffer[pos+1] = (uInt16) myPalette[v];
|
||||
}
|
||||
}
|
||||
|
||||
// Texturemap complete texture to surface so we have free scaling
|
||||
// and antialiasing
|
||||
glBindTexture(GL_TEXTURE_2D, myTextureID);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
|
||||
GL_RGB, GL_UNSIGNED_SHORT_5_6_5, myTexture->pixels);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||
glColor3f(0.0, 0.0, 0.0);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
|
||||
glTexCoord2f(myTexCoord[2], myTexCoord[1]); glVertex2i(myWidth, 0);
|
||||
glTexCoord2f(myTexCoord[2], myTexCoord[3]); glVertex2i(myWidth, myHeight);
|
||||
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, myHeight);
|
||||
glEnd();
|
||||
|
||||
// The frame doesn't need to be completely redrawn anymore
|
||||
theRedrawEntireFrameIndicator = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::preFrameUpdate()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::postFrameUpdate()
|
||||
{
|
||||
// Now show all changes made to the textures
|
||||
SDL_GL_SwapBuffers();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||
{
|
||||
// First draw the box in the background, alpha-blended
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
|
||||
glColor4f(0.0, 0.0, 0.0, 0.7);
|
||||
glRecti(x, y, x+w, y+h);
|
||||
|
||||
// Now draw the outer edges
|
||||
glLineWidth(theZoomLevel/2);
|
||||
glColor4f(0.8, 0.8, 0.8, 1.0);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2i(x, y ); // Top Left
|
||||
glVertex2i(x+w, y ); // Top Right
|
||||
glVertex2i(x+w, y+h); // Bottom Right
|
||||
glVertex2i(x, y+h); // Bottom Left
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawText(uInt32 x, uInt32 y, const string& message)
|
||||
{
|
||||
for(uInt32 i = 0; i < message.length(); i++)
|
||||
drawChar(x + i*8, y, (uInt32) message[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c)
|
||||
{
|
||||
if(c >= 256 )
|
||||
return;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, myFontTextureID[c]);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0, 0); glVertex2i(x, y );
|
||||
glTexCoord2f(1, 0); glVertex2i(x+8, y );
|
||||
glTexCoord2f(1, 1); glVertex2i(x+8, y+8);
|
||||
glTexCoord2f(0, 1); glVertex2i(x, y+8);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferGL::createTextures()
|
||||
{
|
||||
if(myTexture)
|
||||
SDL_FreeSurface(myTexture);
|
||||
|
||||
glDeleteTextures(1, &myTextureID);
|
||||
glDeleteTextures(256, myFontTextureID);
|
||||
|
||||
uInt32 w = power_of_two(myWidth);
|
||||
uInt32 h = power_of_two(myHeight);
|
||||
|
||||
myTexCoord[0] = 0.0f;
|
||||
myTexCoord[1] = 0.0f;
|
||||
myTexCoord[2] = (GLfloat) myWidth / w;
|
||||
myTexCoord[3] = (GLfloat) myHeight / h;
|
||||
|
||||
myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 16,
|
||||
0x0000F800, 0x000007E0, 0x0000001F, 0x00000000);
|
||||
|
||||
if(myTexture == NULL)
|
||||
return false;
|
||||
|
||||
// Create an OpenGL texture from the SDL texture
|
||||
bool showinfo = myConsole->settings().getBool("showinfo");
|
||||
string filter = myConsole->settings().getString("gl_filter");
|
||||
if(filter == "linear")
|
||||
{
|
||||
myFilterParam = GL_LINEAR;
|
||||
if(showinfo)
|
||||
cout << "Using GL_LINEAR filtering.\n";
|
||||
}
|
||||
else if(filter == "nearest")
|
||||
{
|
||||
myFilterParam = GL_NEAREST;
|
||||
if(showinfo)
|
||||
cout << "Using GL_NEAREST filtering.\n";
|
||||
}
|
||||
|
||||
glGenTextures(1, &myTextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, myTextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myFilterParam);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myFilterParam);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
|
||||
myTexture->pixels);
|
||||
|
||||
// Now create the font textures. There are 256 fonts of 8x8 pixels.
|
||||
// These will be stored in 256 textures of size 8x8.
|
||||
SDL_Surface* fontTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, 8, 8, 32,
|
||||
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
||||
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
||||
#else
|
||||
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
|
||||
#endif
|
||||
|
||||
if(fontTexture == NULL)
|
||||
return false;
|
||||
|
||||
// Create a texture for each character
|
||||
glGenTextures(256, myFontTextureID);
|
||||
|
||||
for(uInt32 c = 0; c < 256; c++)
|
||||
{
|
||||
// First clear the texture
|
||||
SDL_Rect tmp;
|
||||
tmp.x = 0; tmp.y = 0; tmp.w = 8; tmp.h = 8;
|
||||
SDL_FillRect(fontTexture, &tmp,
|
||||
SDL_MapRGBA(fontTexture->format, 0xff, 0xff, 0xff, 0x0));
|
||||
|
||||
// Now fill the texture with font data
|
||||
for(uInt32 y = 0; y < 8; y++)
|
||||
{
|
||||
for(uInt32 x = 0; x < 8; x++)
|
||||
{
|
||||
if((ourFontData[(c << 3) + y] >> x) & 1)
|
||||
{
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = tmp.h = 1;
|
||||
SDL_FillRect(fontTexture, &tmp,
|
||||
SDL_MapRGBA(fontTexture->format, 0x10, 0x10, 0x10, 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, myFontTextureID[c]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myFilterParam);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myFilterParam);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
fontTexture->pixels);
|
||||
}
|
||||
|
||||
SDL_FreeSurface(fontTexture);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferGL::toggleFilter()
|
||||
{
|
||||
if(myFilterParam == GL_NEAREST)
|
||||
{
|
||||
myFilterParam = GL_LINEAR;
|
||||
myConsole->settings().setString("gl_filter", "linear");
|
||||
showMessage("GL_LINEAR filtering");
|
||||
}
|
||||
else
|
||||
{
|
||||
myFilterParam = GL_NEAREST;
|
||||
myConsole->settings().setString("gl_filter", "nearest");
|
||||
showMessage("GL_NEAREST filtering");
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, myTextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myFilterParam);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myFilterParam);
|
||||
|
||||
for(uInt32 i = 0; i < 256; i++)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, myFontTextureID[i]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myFilterParam);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myFilterParam);
|
||||
}
|
||||
|
||||
// The filtering has changed, so redraw the entire screen
|
||||
theRedrawEntireFrameIndicator = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SDL_Rect FrameBufferGL::viewport(uInt32 width, uInt32 height)
|
||||
{
|
||||
SDL_Rect rect;
|
||||
rect.x = rect.y = 0;
|
||||
rect.w = width; rect.h = height;
|
||||
|
||||
struct Screenmode
|
||||
{
|
||||
uInt32 w;
|
||||
uInt32 h;
|
||||
};
|
||||
|
||||
// List of valid fullscreen OpenGL modes
|
||||
Screenmode myScreenmode[6] = {
|
||||
{320, 240 },
|
||||
{640, 480 },
|
||||
{800, 600 },
|
||||
{1024, 768 },
|
||||
{1280, 1024},
|
||||
{1600, 1200}
|
||||
};
|
||||
|
||||
for(uInt32 i = 0; i < 6; i++)
|
||||
{
|
||||
if(width <= myScreenmode[i].w && height <= myScreenmode[i].h)
|
||||
{
|
||||
rect.x = (myScreenmode[i].w - width) / 2;
|
||||
rect.y = (myScreenmode[i].h - height) / 2;
|
||||
rect.w = myScreenmode[i].w;
|
||||
rect.h = myScreenmode[i].h;
|
||||
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, it probably indicates an error
|
||||
// But we have to return something ...
|
||||
return rect;
|
||||
}
|
|
@ -1,169 +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: FrameBufferGL.hxx,v 1.9 2004-04-15 22:52:43 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_GL_HXX
|
||||
#define FRAMEBUFFER_GL_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
|
||||
/**
|
||||
This class implements an SDL OpenGL framebuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferGL.hxx,v 1.9 2004-04-15 22:52:43 stephena Exp $
|
||||
*/
|
||||
class FrameBufferGL : public FrameBufferSDL
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Creates a new SDL OpenGL framebuffer
|
||||
*/
|
||||
FrameBufferGL();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~FrameBufferGL();
|
||||
|
||||
/**
|
||||
Switches between the two filtering options in OpenGL.
|
||||
Currently, these are GL_NEAREST and GL_LINEAR.
|
||||
*/
|
||||
void toggleFilter();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBufferSDL.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen();
|
||||
|
||||
/**
|
||||
This routine is called to map a given r,g,b triple to the screen palette.
|
||||
|
||||
@param r The red component of the color.
|
||||
@param g The green component of the color.
|
||||
@param b The blue component of the color.
|
||||
*/
|
||||
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b)
|
||||
{ return SDL_MapRGB(myTexture->format, r, g, b); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine should be called once the console is created to setup
|
||||
the video system for us to use. Return false if any operation fails,
|
||||
otherwise return true.
|
||||
*/
|
||||
virtual bool init();
|
||||
|
||||
/**
|
||||
This routine should be called anytime the MediaSource needs to be redrawn
|
||||
to the screen.
|
||||
*/
|
||||
virtual void drawMediaSource();
|
||||
|
||||
/**
|
||||
This routine should be called to draw a rectangular box with sides
|
||||
at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param w The width of the box
|
||||
@param h The height of the box
|
||||
*/
|
||||
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
|
||||
|
||||
/**
|
||||
This routine should be called to draw text at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param message The message text
|
||||
*/
|
||||
virtual void drawText(uInt32 x, uInt32 y, const string& message);
|
||||
|
||||
/**
|
||||
This routine should be called to draw character 'c' at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param c The character to draw
|
||||
*/
|
||||
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c);
|
||||
|
||||
/**
|
||||
This routine is called before any drawing is done (per-frame).
|
||||
*/
|
||||
virtual void preFrameUpdate();
|
||||
|
||||
/**
|
||||
This routine is called after any drawing is done (per-frame).
|
||||
*/
|
||||
virtual void postFrameUpdate();
|
||||
|
||||
private:
|
||||
|
||||
bool createTextures();
|
||||
|
||||
SDL_Rect viewport(uInt32 width, uInt32 height);
|
||||
|
||||
uInt32 power_of_two(uInt32 input)
|
||||
{
|
||||
uInt32 value = 1;
|
||||
while( value < input )
|
||||
value <<= 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
// The main texture buffer
|
||||
SDL_Surface* myTexture;
|
||||
|
||||
// The depth of the texture buffer
|
||||
uInt32 myDepth;
|
||||
|
||||
// The size of color components for OpenGL
|
||||
uInt32 myRGB[4];
|
||||
|
||||
// The OpenGL main texture handle
|
||||
GLuint myTextureID;
|
||||
|
||||
// OpenGL texture coordinates for the main surface
|
||||
GLfloat myTexCoord[4];
|
||||
|
||||
// The OpenGL font texture handles (one for each character)
|
||||
GLuint myFontTextureID[256];
|
||||
|
||||
// The texture filtering to use
|
||||
GLint myFilterParam;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,268 +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: FrameBufferSDL.cxx,v 1.14 2004-04-26 12:49:46 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
#include "stella.xpm" // The Stella icon
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSDL::FrameBufferSDL()
|
||||
: x11Available(false),
|
||||
theZoomLevel(1),
|
||||
theMaxZoomLevel(1),
|
||||
theAspectRatio(1.0),
|
||||
myPauseStatus(false)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSDL::~FrameBufferSDL()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::pauseEvent(bool status)
|
||||
{
|
||||
myPauseStatus = status;
|
||||
setupPalette();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::setupPalette()
|
||||
{
|
||||
// Shade the palette to 75% normal value in pause mode
|
||||
float shade = 1.0;
|
||||
if(myPauseStatus)
|
||||
shade = 0.75;
|
||||
|
||||
const uInt32* gamePalette = myMediaSource->palette();
|
||||
for(uInt32 i = 0; i < 256; ++i)
|
||||
{
|
||||
Uint8 r, g, b;
|
||||
|
||||
r = (Uint8) (((gamePalette[i] & 0x00ff0000) >> 16) * shade);
|
||||
g = (Uint8) (((gamePalette[i] & 0x0000ff00) >> 8) * shade);
|
||||
b = (Uint8) ((gamePalette[i] & 0x000000ff) * shade);
|
||||
|
||||
myPalette[i] = mapRGB(r, g, b);
|
||||
}
|
||||
|
||||
theRedrawEntireFrameIndicator = true;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::toggleFullscreen()
|
||||
{
|
||||
bool isFullscreen = !myConsole->settings().getBool("fullscreen");
|
||||
|
||||
// Update the settings
|
||||
myConsole->settings().setBool("fullscreen", isFullscreen);
|
||||
|
||||
if(isFullscreen)
|
||||
mySDLFlags |= SDL_FULLSCREEN;
|
||||
else
|
||||
mySDLFlags &= ~SDL_FULLSCREEN;
|
||||
|
||||
if(!createScreen())
|
||||
return;
|
||||
|
||||
if(isFullscreen) // now in fullscreen mode
|
||||
{
|
||||
grabMouse(true);
|
||||
showCursor(false);
|
||||
}
|
||||
else // now in windowed mode
|
||||
{
|
||||
grabMouse(myConsole->settings().getBool("grabmouse"));
|
||||
showCursor(!myConsole->settings().getBool("hidecursor"));
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::resize(int mode)
|
||||
{
|
||||
// reset size to that given in properties
|
||||
// this is a special case of allowing a resize while in fullscreen mode
|
||||
if(mode == 0)
|
||||
{
|
||||
myWidth = myMediaSource->width() << 1;
|
||||
myHeight = myMediaSource->height();
|
||||
}
|
||||
else if(mode == 1) // increase size
|
||||
{
|
||||
if(myConsole->settings().getBool("fullscreen"))
|
||||
return;
|
||||
|
||||
if(theZoomLevel == theMaxZoomLevel)
|
||||
theZoomLevel = 1;
|
||||
else
|
||||
theZoomLevel++;
|
||||
}
|
||||
else if(mode == -1) // decrease size
|
||||
{
|
||||
if(myConsole->settings().getBool("fullscreen"))
|
||||
return;
|
||||
|
||||
if(theZoomLevel == 1)
|
||||
theZoomLevel = theMaxZoomLevel;
|
||||
else
|
||||
theZoomLevel--;
|
||||
}
|
||||
|
||||
if(!createScreen())
|
||||
return;
|
||||
|
||||
// Update the settings
|
||||
myConsole->settings().setInt("zoom", theZoomLevel);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::showCursor(bool show)
|
||||
{
|
||||
if(show)
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
else
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::grabMouse(bool grab)
|
||||
{
|
||||
if(grab)
|
||||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||||
else
|
||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSDL::fullScreen()
|
||||
{
|
||||
return myConsole->settings().getBool("fullscreen");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 FrameBufferSDL::maxWindowSizeForScreen()
|
||||
{
|
||||
if(!x11Available)
|
||||
return 4;
|
||||
|
||||
#ifdef UNIX
|
||||
// Otherwise, lock the screen and get the width and height
|
||||
myWMInfo.info.x11.lock_func();
|
||||
Display* theX11Display = myWMInfo.info.x11.display;
|
||||
myWMInfo.info.x11.unlock_func();
|
||||
|
||||
int screenWidth = DisplayWidth(theX11Display, DefaultScreen(theX11Display));
|
||||
int screenHeight = DisplayHeight(theX11Display, DefaultScreen(theX11Display));
|
||||
|
||||
uInt32 multiplier = screenWidth / myWidth;
|
||||
bool found = false;
|
||||
|
||||
while(!found && (multiplier > 0))
|
||||
{
|
||||
// Figure out the desired size of the window
|
||||
int width = (int) (myWidth * multiplier * theAspectRatio);
|
||||
int height = myHeight * multiplier;
|
||||
|
||||
if((width < screenWidth) && (height < screenHeight))
|
||||
found = true;
|
||||
else
|
||||
multiplier--;
|
||||
}
|
||||
|
||||
if(found)
|
||||
return multiplier;
|
||||
else
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSDL::setWindowAttributes()
|
||||
{
|
||||
// Set the window title
|
||||
ostringstream name;
|
||||
name << "Stella: \"" << myConsole->properties().get("Cartridge.Name") << "\"";
|
||||
SDL_WM_SetCaption(name.str().c_str(), "stella");
|
||||
|
||||
#ifndef MAC_OSX
|
||||
// Set the window icon
|
||||
uInt32 w, h, ncols, nbytes;
|
||||
uInt32 rgba[256], icon[32 * 32];
|
||||
uInt8 mask[32][4];
|
||||
|
||||
sscanf(stella_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes);
|
||||
if((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1))
|
||||
{
|
||||
cerr << "ERROR: Couldn't load the icon.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < ncols; i++)
|
||||
{
|
||||
unsigned char code;
|
||||
char color[32];
|
||||
uInt32 col;
|
||||
|
||||
sscanf(stella_icon[1 + i], "%c c %s", &code, color);
|
||||
if(!strcmp(color, "None"))
|
||||
col = 0x00000000;
|
||||
else if(!strcmp(color, "black"))
|
||||
col = 0xFF000000;
|
||||
else if (color[0] == '#')
|
||||
{
|
||||
sscanf(color + 1, "%06x", &col);
|
||||
col |= 0xFF000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "ERROR: Couldn't load the icon.\n";
|
||||
return;
|
||||
}
|
||||
rgba[code] = col;
|
||||
}
|
||||
|
||||
memset(mask, 0, sizeof(mask));
|
||||
for(h = 0; h < 32; h++)
|
||||
{
|
||||
const char* line = stella_icon[1 + ncols + h];
|
||||
for(w = 0; w < 32; w++)
|
||||
{
|
||||
icon[w + 32 * h] = rgba[(int)line[w]];
|
||||
if(rgba[(int)line[w]] & 0xFF000000)
|
||||
mask[h][w >> 3] |= 1 << (7 - (w & 0x07));
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32,
|
||||
32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
|
||||
SDL_WM_SetIcon(surface, (unsigned char *) mask);
|
||||
SDL_FreeSurface(surface);
|
||||
#endif
|
||||
}
|
|
@ -1,163 +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: FrameBufferSDL.hxx,v 1.11 2004-04-26 12:49:46 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_SDL_HXX
|
||||
#define FRAMEBUFFER_SDL_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class is a base class for the SDL framebuffer and is derived from
|
||||
the core FrameBuffer class.
|
||||
|
||||
It defines all common code shared between the software
|
||||
and OpenGL video modes, as well as required methods defined in
|
||||
the core FrameBuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferSDL.hxx,v 1.11 2004-04-26 12:49:46 stephena Exp $
|
||||
*/
|
||||
class FrameBufferSDL : public FrameBuffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Creates a new SDL framebuffer
|
||||
*/
|
||||
FrameBufferSDL();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~FrameBufferSDL();
|
||||
|
||||
|
||||
/**
|
||||
Toggles between fullscreen and window mode. Grabmouse and hidecursor
|
||||
activated when in fullscreen mode.
|
||||
*/
|
||||
void toggleFullscreen();
|
||||
|
||||
/**
|
||||
This routine is called when the user wants to resize the window.
|
||||
A '1' argument indicates that the window should increase in size, while '-1'
|
||||
indicates that the windows should decrease in size. A '0' indicates that
|
||||
the window should be sized according to the current properties.
|
||||
Can't resize in fullscreen mode. Will only resize up to the maximum size
|
||||
of the screen.
|
||||
*/
|
||||
void resize(int mode);
|
||||
|
||||
/**
|
||||
Shows or hides the cursor based on the given boolean value.
|
||||
*/
|
||||
void showCursor(bool show);
|
||||
|
||||
/**
|
||||
Grabs or ungrabs the mouse based on the given boolean value.
|
||||
*/
|
||||
void grabMouse(bool grab);
|
||||
|
||||
/**
|
||||
Answers if the display is currently in fullscreen mode.
|
||||
*/
|
||||
bool fullScreen();
|
||||
|
||||
/**
|
||||
Answers the current zoom level of the SDL
|
||||
*/
|
||||
uInt32 zoomLevel() { return theZoomLevel; }
|
||||
|
||||
/**
|
||||
Calculate the maximum window size that the current screen can hold.
|
||||
Only works in X11 for now. If not running under X11, always return 4.
|
||||
*/
|
||||
uInt32 maxWindowSizeForScreen();
|
||||
|
||||
/**
|
||||
Set the title and icon for the main SDL window.
|
||||
*/
|
||||
void setWindowAttributes();
|
||||
|
||||
/**
|
||||
Set up the palette for a screen of any depth > 8.
|
||||
*/
|
||||
void setupPalette();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called when the emulation has been paused.
|
||||
|
||||
@param status Toggle pause based on status
|
||||
*/
|
||||
void pauseEvent(bool status);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods must be defined in child classes
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen() = 0;
|
||||
|
||||
/**
|
||||
This routine is called to map a given r,g,b triple to the screen palette.
|
||||
|
||||
@param r The red component of the color.
|
||||
@param g The green component of the color.
|
||||
@param b The blue component of the color.
|
||||
*/
|
||||
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) = 0;
|
||||
|
||||
protected:
|
||||
// The SDL video buffer
|
||||
SDL_Surface* myScreen;
|
||||
|
||||
// SDL initialization flags
|
||||
uInt32 mySDLFlags;
|
||||
|
||||
// SDL palette
|
||||
Uint32 myPalette[256];
|
||||
|
||||
// Used to get window-manager specifics
|
||||
SDL_SysWMinfo myWMInfo;
|
||||
|
||||
// Indicates if we are running under X11
|
||||
bool x11Available;
|
||||
|
||||
// Indicates the current zoom level of the SDL screen
|
||||
uInt32 theZoomLevel;
|
||||
|
||||
// Indicates the maximum zoom of the SDL screen
|
||||
uInt32 theMaxZoomLevel;
|
||||
|
||||
// The aspect ratio of the window
|
||||
float theAspectRatio;
|
||||
|
||||
// Indicates whether the emulation has paused
|
||||
bool myPauseStatus;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,440 +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: FrameBufferSoft.cxx,v 1.7 2004-04-26 12:49:46 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "FrameBufferSoft.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSoft::FrameBufferSoft()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FrameBufferSoft::~FrameBufferSoft()
|
||||
{
|
||||
if(myRectList)
|
||||
delete myRectList;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSoft::createScreen()
|
||||
{
|
||||
int w = myWidth * theZoomLevel;
|
||||
int h = myHeight * theZoomLevel;
|
||||
|
||||
myScreen = SDL_SetVideoMode(w, h, 0, mySDLFlags);
|
||||
if(myScreen == NULL)
|
||||
{
|
||||
cerr << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
theRedrawEntireFrameIndicator = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool FrameBufferSoft::init()
|
||||
{
|
||||
// Get the desired width and height of the display
|
||||
myWidth = myMediaSource->width() << 1;
|
||||
myHeight = myMediaSource->height();
|
||||
|
||||
// Now create the software SDL screen
|
||||
Uint32 initflags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
|
||||
if(SDL_Init(initflags) < 0)
|
||||
return false;
|
||||
|
||||
// Check which system we are running under
|
||||
x11Available = false;
|
||||
#if UNIX && (!__APPLE__)
|
||||
SDL_VERSION(&myWMInfo.version);
|
||||
if(SDL_GetWMInfo(&myWMInfo) > 0)
|
||||
if(myWMInfo.subsystem == SDL_SYSWM_X11)
|
||||
x11Available = true;
|
||||
#endif
|
||||
|
||||
// Get the maximum size of a window for THIS screen
|
||||
theMaxZoomLevel = maxWindowSizeForScreen();
|
||||
|
||||
// Check to see if window size will fit in the screen
|
||||
if((uInt32)myConsole->settings().getInt("zoom") > theMaxZoomLevel)
|
||||
theZoomLevel = theMaxZoomLevel;
|
||||
else
|
||||
theZoomLevel = myConsole->settings().getInt("zoom");
|
||||
|
||||
mySDLFlags = SDL_SWSURFACE;
|
||||
mySDLFlags |= myConsole->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
|
||||
|
||||
// Set up the rectangle list to be used in the dirty update
|
||||
myRectList = new RectList();
|
||||
if(!myRectList)
|
||||
{
|
||||
cerr << "ERROR: Unable to get memory for SDL rects" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the window title and icon
|
||||
setWindowAttributes();
|
||||
|
||||
// Create the screen
|
||||
if(!createScreen())
|
||||
return false;
|
||||
setupPalette();
|
||||
|
||||
// Make sure that theUseFullScreenFlag sets up fullscreen mode correctly
|
||||
if(myConsole->settings().getBool("fullscreen"))
|
||||
{
|
||||
grabMouse(true);
|
||||
showCursor(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep mouse in game window if grabmouse is selected
|
||||
grabMouse(myConsole->settings().getBool("grabmouse"));
|
||||
|
||||
// Show or hide the cursor depending on the 'hidecursor' argument
|
||||
showCursor(!myConsole->settings().getBool("hidecursor"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawMediaSource()
|
||||
{
|
||||
uInt8* currentFrame = myMediaSource->currentFrameBuffer();
|
||||
uInt8* previousFrame = myMediaSource->previousFrameBuffer();
|
||||
uInt16 screenMultiple = (uInt16) theZoomLevel;
|
||||
|
||||
uInt32 width = myMediaSource->width();
|
||||
uInt32 height = myMediaSource->height();
|
||||
|
||||
struct Rectangle
|
||||
{
|
||||
uInt8 color;
|
||||
uInt16 x, y, width, height;
|
||||
} rectangles[2][160];
|
||||
|
||||
// This array represents the rectangles that need displaying
|
||||
// on the current scanline we're processing
|
||||
Rectangle* currentRectangles = rectangles[0];
|
||||
|
||||
// This array represents the rectangles that are still active
|
||||
// from the previous scanlines we have processed
|
||||
Rectangle* activeRectangles = rectangles[1];
|
||||
|
||||
// Indicates the number of active rectangles
|
||||
uInt16 activeCount = 0;
|
||||
|
||||
// This update procedure requires theWidth to be a multiple of four.
|
||||
// This is validated when the properties are loaded.
|
||||
for(uInt16 y = 0; y < height; ++y)
|
||||
{
|
||||
// Indicates the number of current rectangles
|
||||
uInt16 currentCount = 0;
|
||||
|
||||
// Look at four pixels at a time to see if anything has changed
|
||||
uInt32* current = (uInt32*)(currentFrame);
|
||||
uInt32* previous = (uInt32*)(previousFrame);
|
||||
|
||||
for(uInt16 x = 0; x < width; x += 4, ++current, ++previous)
|
||||
{
|
||||
// Has something changed in this set of four pixels?
|
||||
if((*current != *previous) || theRedrawEntireFrameIndicator)
|
||||
{
|
||||
uInt8* c = (uInt8*)current;
|
||||
uInt8* p = (uInt8*)previous;
|
||||
|
||||
// Look at each of the bytes that make up the uInt32
|
||||
for(uInt16 i = 0; i < 4; ++i, ++c, ++p)
|
||||
{
|
||||
// See if this pixel has changed
|
||||
if((*c != *p) || theRedrawEntireFrameIndicator)
|
||||
{
|
||||
// Can we extend a rectangle or do we have to create a new one?
|
||||
if((currentCount != 0) &&
|
||||
(currentRectangles[currentCount - 1].color == *c) &&
|
||||
((currentRectangles[currentCount - 1].x +
|
||||
currentRectangles[currentCount - 1].width) == (x + i)))
|
||||
{
|
||||
currentRectangles[currentCount - 1].width += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRectangles[currentCount].x = x + i;
|
||||
currentRectangles[currentCount].y = y;
|
||||
currentRectangles[currentCount].width = 1;
|
||||
currentRectangles[currentCount].height = 1;
|
||||
currentRectangles[currentCount].color = *c;
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge the active and current rectangles flushing any that are of no use
|
||||
uInt16 activeIndex = 0;
|
||||
|
||||
for(uInt16 t = 0; (t < currentCount) && (activeIndex < activeCount); ++t)
|
||||
{
|
||||
Rectangle& current = currentRectangles[t];
|
||||
Rectangle& active = activeRectangles[activeIndex];
|
||||
|
||||
// Can we merge the current rectangle with an active one?
|
||||
if((current.x == active.x) && (current.width == active.width) &&
|
||||
(current.color == active.color))
|
||||
{
|
||||
current.y = active.y;
|
||||
current.height = active.height + 1;
|
||||
|
||||
++activeIndex;
|
||||
}
|
||||
// Is it impossible for this active rectangle to be merged?
|
||||
else if(current.x >= active.x)
|
||||
{
|
||||
// Flush the active rectangle
|
||||
SDL_Rect temp;
|
||||
|
||||
temp.x = active.x * screenMultiple << 1;
|
||||
temp.y = active.y * screenMultiple;
|
||||
temp.w = active.width * screenMultiple << 1;
|
||||
temp.h = active.height * screenMultiple;
|
||||
|
||||
myRectList->add(&temp);
|
||||
SDL_FillRect(myScreen, &temp, myPalette[active.color]);
|
||||
|
||||
++activeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any remaining active rectangles
|
||||
for(uInt16 s = activeIndex; s < activeCount; ++s)
|
||||
{
|
||||
Rectangle& active = activeRectangles[s];
|
||||
|
||||
SDL_Rect temp;
|
||||
temp.x = active.x * screenMultiple << 1;
|
||||
temp.y = active.y * screenMultiple;
|
||||
temp.w = active.width * screenMultiple << 1;
|
||||
temp.h = active.height * screenMultiple;
|
||||
|
||||
myRectList->add(&temp);
|
||||
SDL_FillRect(myScreen, &temp, myPalette[active.color]);
|
||||
}
|
||||
|
||||
// We can now make the current rectangles into the active rectangles
|
||||
Rectangle* tmp = currentRectangles;
|
||||
currentRectangles = activeRectangles;
|
||||
activeRectangles = tmp;
|
||||
activeCount = currentCount;
|
||||
|
||||
currentFrame += width;
|
||||
previousFrame += width;
|
||||
}
|
||||
|
||||
// Flush any rectangles that are still active
|
||||
for(uInt16 t = 0; t < activeCount; ++t)
|
||||
{
|
||||
Rectangle& active = activeRectangles[t];
|
||||
|
||||
SDL_Rect temp;
|
||||
temp.x = active.x * screenMultiple << 1;
|
||||
temp.y = active.y * screenMultiple;
|
||||
temp.w = active.width * screenMultiple << 1;
|
||||
temp.h = active.height * screenMultiple;
|
||||
|
||||
myRectList->add(&temp);
|
||||
SDL_FillRect(myScreen, &temp, myPalette[active.color]);
|
||||
}
|
||||
|
||||
// The frame doesn't need to be completely redrawn anymore
|
||||
theRedrawEntireFrameIndicator = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::preFrameUpdate()
|
||||
{
|
||||
// Start a new rectlist on each display update
|
||||
myRectList->start();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::postFrameUpdate()
|
||||
{
|
||||
// Now update all the rectangles at once
|
||||
SDL_UpdateRects(myScreen, myRectList->numRects(), myRectList->rects());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
|
||||
{
|
||||
SDL_Rect tmp;
|
||||
|
||||
// Scale all values to the current window size
|
||||
x *= theZoomLevel;
|
||||
y *= theZoomLevel;
|
||||
w *= theZoomLevel;
|
||||
h *= theZoomLevel;
|
||||
|
||||
// First draw the underlying box
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = w;
|
||||
tmp.h = h;
|
||||
myRectList->add(&tmp);
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myBGColor]);
|
||||
|
||||
// Now draw the bounding sides
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = w;
|
||||
tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // top
|
||||
|
||||
tmp.x = x;
|
||||
tmp.y = y + h - theZoomLevel;
|
||||
tmp.w = w;
|
||||
tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // bottom
|
||||
|
||||
tmp.x = x;
|
||||
tmp.y = y;
|
||||
tmp.w = theZoomLevel;
|
||||
tmp.h = h;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // left
|
||||
|
||||
tmp.x = x + w - theZoomLevel;
|
||||
tmp.y = y;
|
||||
tmp.w = theZoomLevel;
|
||||
tmp.h = h;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]); // right
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawText(uInt32 xorig, uInt32 yorig, const string& message)
|
||||
{
|
||||
SDL_Rect tmp;
|
||||
|
||||
uInt8 length = message.length();
|
||||
for(uInt32 x = 0; x < length; x++)
|
||||
{
|
||||
for(uInt32 y = 0; y < 8; y++)
|
||||
{
|
||||
for(uInt32 z = 0; z < 8; z++)
|
||||
{
|
||||
char letter = message[x];
|
||||
if((ourFontData[(letter << 3) + y] >> z) & 1)
|
||||
{
|
||||
tmp.x = ((x<<3) + z + xorig) * theZoomLevel;
|
||||
tmp.y = (y + yorig) * theZoomLevel;
|
||||
tmp.w = tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameBufferSoft::drawChar(uInt32 xorig, uInt32 yorig, uInt32 c)
|
||||
{
|
||||
if(c >= 256 )
|
||||
return;
|
||||
|
||||
SDL_Rect tmp;
|
||||
|
||||
for(uInt32 y = 0; y < 8; y++)
|
||||
{
|
||||
for(uInt32 z = 0; z < 8; z++)
|
||||
{
|
||||
if((ourFontData[(c << 3) + y] >> z) & 1)
|
||||
{
|
||||
tmp.x = (z + xorig) * theZoomLevel;
|
||||
tmp.y = (y + yorig) * theZoomLevel;
|
||||
tmp.w = tmp.h = theZoomLevel;
|
||||
SDL_FillRect(myScreen, &tmp, myPalette[myFGColor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RectList::RectList(Uint32 size)
|
||||
{
|
||||
currentSize = size;
|
||||
currentRect = 0;
|
||||
|
||||
rectArray = new SDL_Rect[currentSize];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RectList::~RectList()
|
||||
{
|
||||
delete[] rectArray;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RectList::add(SDL_Rect* newRect)
|
||||
{
|
||||
if(currentRect >= currentSize)
|
||||
{
|
||||
currentSize = currentSize * 2;
|
||||
SDL_Rect *temp = new SDL_Rect[currentSize];
|
||||
|
||||
for(Uint32 i = 0; i < currentRect; ++i)
|
||||
temp[i] = rectArray[i];
|
||||
|
||||
delete[] rectArray;
|
||||
rectArray = temp;
|
||||
}
|
||||
|
||||
rectArray[currentRect].x = newRect->x;
|
||||
rectArray[currentRect].y = newRect->y;
|
||||
rectArray[currentRect].w = newRect->w;
|
||||
rectArray[currentRect].h = newRect->h;
|
||||
|
||||
++currentRect;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SDL_Rect* RectList::rects()
|
||||
{
|
||||
return rectArray;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Uint32 RectList::numRects()
|
||||
{
|
||||
return currentRect;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RectList::start()
|
||||
{
|
||||
currentRect = 0;
|
||||
}
|
|
@ -1,153 +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: FrameBufferSoft.hxx,v 1.3 2004-04-15 22:52:43 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef FRAMEBUFFER_SOFT_HXX
|
||||
#define FRAMEBUFFER_SOFT_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
class MediaSource;
|
||||
class RectList;
|
||||
|
||||
|
||||
/**
|
||||
This class implements an SDL software framebuffer.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: FrameBufferSoft.hxx,v 1.3 2004-04-15 22:52:43 stephena Exp $
|
||||
*/
|
||||
class FrameBufferSoft : public FrameBufferSDL
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Creates a new SDL software framebuffer
|
||||
*/
|
||||
FrameBufferSoft();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~FrameBufferSoft();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBufferSDL.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine is called whenever the screen needs to be recreated.
|
||||
It updates the global screen variable.
|
||||
*/
|
||||
virtual bool createScreen();
|
||||
|
||||
/**
|
||||
This routine is called to map a given r,g,b triple to the screen palette.
|
||||
|
||||
@param r The red component of the color.
|
||||
@param g The green component of the color.
|
||||
@param b The blue component of the color.
|
||||
*/
|
||||
virtual Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b)
|
||||
{ return SDL_MapRGB(myScreen->format, r, g, b); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following methods are derived from FrameBuffer.hxx
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
This routine should be called once the console is created to setup
|
||||
the video system for us to use. Return false if any operation fails,
|
||||
otherwise return true.
|
||||
*/
|
||||
virtual bool init();
|
||||
|
||||
/**
|
||||
This routine should be called anytime the MediaSource needs to be redrawn
|
||||
to the screen.
|
||||
*/
|
||||
virtual void drawMediaSource();
|
||||
|
||||
/**
|
||||
This routine should be called to draw a rectangular box with sides
|
||||
at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param w The width of the box
|
||||
@param h The height of the box
|
||||
*/
|
||||
virtual void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
|
||||
|
||||
/**
|
||||
This routine should be called to draw text at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param message The message text
|
||||
*/
|
||||
virtual void drawText(uInt32 x, uInt32 y, const string& message);
|
||||
|
||||
/**
|
||||
This routine should be called to draw character 'c' at the specified coordinates.
|
||||
|
||||
@param x The x coordinate
|
||||
@param y The y coordinate
|
||||
@param c The character to draw
|
||||
*/
|
||||
virtual void drawChar(uInt32 x, uInt32 y, uInt32 c);
|
||||
|
||||
/**
|
||||
This routine is called before any drawing is done (per-frame).
|
||||
*/
|
||||
virtual void preFrameUpdate();
|
||||
|
||||
/**
|
||||
This routine is called after any drawing is done (per-frame).
|
||||
*/
|
||||
virtual void postFrameUpdate();
|
||||
|
||||
private:
|
||||
// Used in the dirty update of the SDL surface
|
||||
RectList* myRectList;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
class RectList
|
||||
{
|
||||
public:
|
||||
RectList(Uint32 size = 512);
|
||||
~RectList();
|
||||
|
||||
void add(SDL_Rect* rect);
|
||||
|
||||
SDL_Rect* rects();
|
||||
Uint32 numRects();
|
||||
void start();
|
||||
|
||||
private:
|
||||
Uint32 currentSize, currentRect;
|
||||
|
||||
SDL_Rect* rectArray;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,182 +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: SettingsUNIX.cxx,v 1.9 2004-04-27 00:50:52 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "StellaEvent.hxx"
|
||||
|
||||
#include "Settings.hxx"
|
||||
#include "SettingsUNIX.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsUNIX::SettingsUNIX()
|
||||
{
|
||||
// First set variables that the parent class needs
|
||||
myBaseDir = getenv("HOME");
|
||||
string stelladir = myBaseDir + "/.stella";
|
||||
|
||||
if(access(stelladir.c_str(), R_OK|W_OK|X_OK) != 0 )
|
||||
mkdir(stelladir.c_str(), 0777);
|
||||
|
||||
myStateDir = stelladir + "/state/";
|
||||
if(access(myStateDir.c_str(), R_OK|W_OK|X_OK) != 0 )
|
||||
mkdir(myStateDir.c_str(), 0777);
|
||||
|
||||
myUserPropertiesFile = stelladir + "/stella.pro";
|
||||
mySystemPropertiesFile = "/etc/stella.pro";
|
||||
myUserConfigFile = stelladir + "/stellarc";
|
||||
mySystemConfigFile = "/etc/stellarc";
|
||||
|
||||
// Set up the names of the input and output config files
|
||||
mySettingsOutputFilename = myUserConfigFile;
|
||||
if(access(myUserConfigFile.c_str(), R_OK) == 0)
|
||||
mySettingsInputFilename = myUserConfigFile;
|
||||
else
|
||||
mySettingsInputFilename = mySystemConfigFile;
|
||||
|
||||
mySnapshotFile = "";
|
||||
myStateFile = "";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsUNIX::~SettingsUNIX()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SettingsUNIX::usage(string& message)
|
||||
{
|
||||
cout << endl
|
||||
<< message << endl
|
||||
<< endl
|
||||
<< "Valid options are:" << endl
|
||||
<< endl
|
||||
<< " -video <type> Type is one of the following:\n"
|
||||
<< " soft SDL software mode\n"
|
||||
#ifdef DISPLAY_OPENGL
|
||||
<< " gl SDL OpenGL mode\n"
|
||||
<< endl
|
||||
<< " -gl_filter <type> Type is one of the following:\n"
|
||||
<< " nearest Normal scaling (GL_NEAREST)\n"
|
||||
<< " linear Blurred scaling (GL_LINEAR)\n"
|
||||
<< " -gl_aspect <number> Scale the width by the given amount\n"
|
||||
<< endl
|
||||
#endif
|
||||
<< " -sound <0|1> Enable sound generation\n"
|
||||
<< " -fragsize <number> The size of sound fragments (should be a power of two)\n"
|
||||
<< " -bufsize <number> The size of the sound buffer\n"
|
||||
<< " -framerate <number> Display the given number of frames per second\n"
|
||||
<< " -zoom <size> Makes window be 'size' times normal\n"
|
||||
<< " -fullscreen <0|1> Play the game in fullscreen mode\n"
|
||||
<< " -grabmouse <0|1> Keeps the mouse in the game window\n"
|
||||
<< " -hidecursor <0|1> Hides the mouse cursor in the game window\n"
|
||||
<< " -volume <number> Set the volume (0 - 100)\n"
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
<< " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n"
|
||||
<< " or that real Atari 2600 paddles are being used\n"
|
||||
#else
|
||||
<< " -paddle <0|1|2|3> Indicates which paddle the mouse should emulate\n"
|
||||
#endif
|
||||
<< " -altpro <props file> Use the given properties file instead of stella.pro\n"
|
||||
<< " -showinfo <0|1> Shows some game info\n"
|
||||
<< " -accurate <0|1> Accurate game timing (uses more CPU)\n"
|
||||
#ifdef SNAPSHOT_SUPPORT
|
||||
<< " -ssdir <path> The directory to save snapshot files to\n"
|
||||
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n"
|
||||
<< " -sssingle <0|1> Generate single snapshot instead of many\n"
|
||||
#endif
|
||||
<< endl
|
||||
#ifdef DEVELOPER_SUPPORT
|
||||
<< " DEVELOPER options (see Stella manual for details)\n"
|
||||
<< " -Dformat Sets \"Display.Format\"\n"
|
||||
<< " -Dxstart Sets \"Display.XStart\"\n"
|
||||
<< " -Dwidth Sets \"Display.Width\"\n"
|
||||
<< " -Dystart Sets \"Display.YStart\"\n"
|
||||
<< " -Dheight Sets \"Display.Height\"\n"
|
||||
<< " -mergeprops <0|1> Merge changed properties into properties file,\n"
|
||||
<< " or save into a separate file\n"
|
||||
#endif
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string SettingsUNIX::stateFilename(uInt32 state)
|
||||
{
|
||||
if(!myConsole)
|
||||
return "";
|
||||
|
||||
ostringstream buf;
|
||||
buf << myStateDir << myConsole->properties().get("Cartridge.MD5")
|
||||
<< ".st" << state;
|
||||
|
||||
myStateFile = buf.str();
|
||||
return myStateFile;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string SettingsUNIX::snapshotFilename()
|
||||
{
|
||||
if(!myConsole)
|
||||
return "";
|
||||
|
||||
string filename;
|
||||
string path = getString("ssdir");
|
||||
string theSnapshotName = getString("ssname");
|
||||
|
||||
if(theSnapshotName == "romname")
|
||||
path = path + "/" + myConsole->properties().get("Cartridge.Name");
|
||||
else if(theSnapshotName == "md5sum")
|
||||
path = path + "/" + myConsole->properties().get("Cartridge.MD5");
|
||||
|
||||
// Replace all spaces in name with underscores
|
||||
replace(path.begin(), path.end(), ' ', '_');
|
||||
|
||||
// Check whether we want multiple snapshots created
|
||||
if(!getBool("sssingle"))
|
||||
{
|
||||
// Determine if the file already exists, checking each successive filename
|
||||
// until one doesn't exist
|
||||
filename = path + ".png";
|
||||
if(access(filename.c_str(), F_OK) == 0 )
|
||||
{
|
||||
ostringstream buf;
|
||||
for(uInt32 i = 1; ;++i)
|
||||
{
|
||||
buf.str("");
|
||||
buf << path << "_" << i << ".png";
|
||||
if(access(buf.str().c_str(), F_OK) == -1 )
|
||||
break;
|
||||
}
|
||||
filename = buf.str();
|
||||
}
|
||||
}
|
||||
else
|
||||
filename = path + ".png";
|
||||
|
||||
mySnapshotFile = filename;
|
||||
return mySnapshotFile;
|
||||
}
|
|
@ -1,70 +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: SettingsUNIX.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SETTINGS_UNIX_HXX
|
||||
#define SETTINGS_UNIX_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
|
||||
|
||||
/**
|
||||
This class defines UNIX-like OS's (Linux) system specific settings.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: SettingsUNIX.hxx,v 1.1 2003-10-26 19:40:39 stephena Exp $
|
||||
*/
|
||||
class SettingsUNIX : public Settings
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new UNIX settings object
|
||||
*/
|
||||
SettingsUNIX();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SettingsUNIX();
|
||||
|
||||
public:
|
||||
/**
|
||||
This method should be called to get the filename of a state file
|
||||
given the state number.
|
||||
|
||||
@return String representing the full path of the state filename.
|
||||
*/
|
||||
virtual string stateFilename(uInt32 state);
|
||||
|
||||
/**
|
||||
This method should be called to get the filename of a snapshot.
|
||||
|
||||
@return String representing the full path of the snapshot filename.
|
||||
*/
|
||||
virtual string snapshotFilename();
|
||||
|
||||
/**
|
||||
Display the commandline settings for this UNIX version of Stella.
|
||||
|
||||
@param message A short message about this version of Stella
|
||||
*/
|
||||
virtual void usage(string& message);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,188 +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: SettingsWin32.cxx,v 1.4 2004-04-27 00:50:52 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "StellaEvent.hxx"
|
||||
|
||||
#include "Settings.hxx"
|
||||
#include "SettingsWin32.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsWin32::SettingsWin32()
|
||||
{
|
||||
// First set variables that the parent class needs
|
||||
myBaseDir = ".\\";
|
||||
string stelladir = myBaseDir;
|
||||
|
||||
// if(access(stelladir.c_str(), R_OK|W_OK|X_OK) != 0 )
|
||||
// mkdir(stelladir.c_str(), 0777);
|
||||
|
||||
myStateDir = stelladir + "state\\";
|
||||
// if(access(myStateDir.c_str(), R_OK|W_OK|X_OK) != 0 )
|
||||
// mkdir(myStateDir.c_str(), 0777);
|
||||
|
||||
myUserPropertiesFile = stelladir + "stella.pro";
|
||||
mySystemPropertiesFile = stelladir + "stella.pro";
|
||||
myUserConfigFile = stelladir + "stellarc";
|
||||
mySystemConfigFile = stelladir + "stellarc";
|
||||
|
||||
// Set up the names of the input and output config files
|
||||
mySettingsOutputFilename = myUserConfigFile;
|
||||
// if(access(myUserConfigFile.c_str(), R_OK) == 0)
|
||||
mySettingsInputFilename = myUserConfigFile;
|
||||
// else
|
||||
// mySettingsInputFilename = mySystemConfigFile;
|
||||
|
||||
mySnapshotFile = "";
|
||||
myStateFile = "";
|
||||
|
||||
// Now create Win32 specific settings
|
||||
set("accurate", "false"); // Don't change this, or the sound will skip
|
||||
#ifdef SNAPSHOT_SUPPORT
|
||||
set("ssdir", ".\\");
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsWin32::~SettingsWin32()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SettingsWin32::usage(string& message)
|
||||
{
|
||||
cout << endl
|
||||
<< message << endl
|
||||
<< endl
|
||||
<< "Valid options are:" << endl
|
||||
<< endl
|
||||
<< " -video <type> Type is one of the following:\n"
|
||||
<< " soft SDL software mode\n"
|
||||
#ifdef DISPLAY_OPENGL
|
||||
<< " gl SDL OpenGL mode\n"
|
||||
<< endl
|
||||
<< " -gl_filter <type> Type is one of the following:\n"
|
||||
<< " nearest Normal scaling (GL_NEAREST)\n"
|
||||
<< " linear Blurred scaling (GL_LINEAR)\n"
|
||||
<< " -gl_aspect <number> Scale the width by the given amount\n"
|
||||
<< endl
|
||||
#endif
|
||||
<< " -sound <0|1> Enable sound generation\n"
|
||||
<< " -fragsize <number> The size of sound fragments (should be a power of two)\n"
|
||||
<< " -bufsize <number> The size of the sound buffer\n"
|
||||
<< " -framerate <number> Display the given number of frames per second\n"
|
||||
<< " -zoom <size> Makes window be 'size' times normal\n"
|
||||
<< " -fullscreen <0|1> Play the game in fullscreen mode\n"
|
||||
<< " -grabmouse <0|1> Keeps the mouse in the game window\n"
|
||||
<< " -hidecursor <0|1> Hides the mouse cursor in the game window\n"
|
||||
<< " -volume <number> Set the volume (0 - 100)\n"
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
<< " -paddle <0|1|2|3|real> Indicates which paddle the mouse should emulate\n"
|
||||
<< " or that real Atari 2600 paddles are being used\n"
|
||||
#else
|
||||
<< " -paddle <0|1|2|3> Indicates which paddle the mouse should emulate\n"
|
||||
#endif
|
||||
<< " -altpro <props file> Use the given properties file instead of stella.pro\n"
|
||||
<< " -showinfo <0|1> Shows some game info\n"
|
||||
<< " -accurate <0|1> Accurate game timing (uses more CPU)\n"
|
||||
#ifdef SNAPSHOT_SUPPORT
|
||||
<< " -ssdir <path> The directory to save snapshot files to\n"
|
||||
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n"
|
||||
<< " -sssingle <0|1> Generate single snapshot instead of many\n"
|
||||
#endif
|
||||
<< endl
|
||||
#ifdef DEVELOPER_SUPPORT
|
||||
<< " DEVELOPER options (see Stella manual for details)\n"
|
||||
<< " -Dformat Sets \"Display.Format\"\n"
|
||||
<< " -Dxstart Sets \"Display.XStart\"\n"
|
||||
<< " -Dwidth Sets \"Display.Width\"\n"
|
||||
<< " -Dystart Sets \"Display.YStart\"\n"
|
||||
<< " -Dheight Sets \"Display.Height\"\n"
|
||||
<< " -mergeprops <0|1> Merge changed properties into properties file,\n"
|
||||
<< " or save into a separate file\n"
|
||||
#endif
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string SettingsWin32::stateFilename(uInt32 state)
|
||||
{
|
||||
if(!myConsole)
|
||||
return "";
|
||||
|
||||
ostringstream buf;
|
||||
buf << myStateDir << myConsole->properties().get("Cartridge.MD5")
|
||||
<< ".st" << state;
|
||||
|
||||
myStateFile = buf.str();
|
||||
return myStateFile;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string SettingsWin32::snapshotFilename()
|
||||
{
|
||||
if(!myConsole)
|
||||
return "";
|
||||
|
||||
string filename;
|
||||
string path = getString("ssdir");
|
||||
string theSnapshotName = getString("ssname");
|
||||
|
||||
if(theSnapshotName == "romname")
|
||||
path = path + "\\" + myConsole->properties().get("Cartridge.Name");
|
||||
else if(theSnapshotName == "md5sum")
|
||||
path = path + "\\" + myConsole->properties().get("Cartridge.MD5");
|
||||
|
||||
// Replace all spaces in name with underscores
|
||||
replace(path.begin(), path.end(), ' ', '_');
|
||||
|
||||
// Check whether we want multiple snapshots created
|
||||
if(!getBool("sssingle"))
|
||||
{
|
||||
// Determine if the file already exists, checking each successive filename
|
||||
// until one doesn't exist
|
||||
filename = path + ".png";
|
||||
if(access(filename.c_str(), F_OK) == 0 )
|
||||
{
|
||||
ostringstream buf;
|
||||
for(uInt32 i = 1; ;++i)
|
||||
{
|
||||
buf.str("");
|
||||
buf << path << "_" << i << ".png";
|
||||
if(access(buf.str().c_str(), F_OK) == -1 )
|
||||
break;
|
||||
}
|
||||
filename = buf.str();
|
||||
}
|
||||
}
|
||||
else
|
||||
filename = path + ".png";
|
||||
|
||||
mySnapshotFile = filename;
|
||||
return mySnapshotFile;
|
||||
}
|
|
@ -1,70 +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: SettingsWin32.hxx,v 1.1 2003-12-04 22:22:53 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SETTINGS_WIN32_HXX
|
||||
#define SETTINGS_WIN32_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class Console;
|
||||
|
||||
|
||||
/**
|
||||
This class defines Windows system specific settings.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: SettingsWin32.hxx,v 1.1 2003-12-04 22:22:53 stephena Exp $
|
||||
*/
|
||||
class SettingsWin32 : public Settings
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new UNIX settings object
|
||||
*/
|
||||
SettingsWin32();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SettingsWin32();
|
||||
|
||||
public:
|
||||
/**
|
||||
This method should be called to get the filename of a state file
|
||||
given the state number.
|
||||
|
||||
@return String representing the full path of the state filename.
|
||||
*/
|
||||
virtual string stateFilename(uInt32 state);
|
||||
|
||||
/**
|
||||
This method should be called to get the filename of a snapshot.
|
||||
|
||||
@return String representing the full path of the snapshot filename.
|
||||
*/
|
||||
virtual string snapshotFilename();
|
||||
|
||||
/**
|
||||
Display the commandline settings for this UNIX version of Stella.
|
||||
|
||||
@param message A short message about this version of Stella
|
||||
*/
|
||||
virtual void usage(string& message);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,992 +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-2002 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: mainSDL.cxx,v 1.76 2004-05-13 12:38:17 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Event.hxx"
|
||||
#include "StellaEvent.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FrameBufferSDL.hxx"
|
||||
#include "FrameBufferSoft.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "Sound.hxx"
|
||||
#include "SoundSDL.hxx"
|
||||
#include "Settings.hxx"
|
||||
|
||||
#ifdef DISPLAY_OPENGL
|
||||
#include "FrameBufferGL.hxx"
|
||||
|
||||
// Indicates whether to use OpenGL mode
|
||||
static bool theUseOpenGLFlag;
|
||||
#endif
|
||||
|
||||
#if defined(UNIX)
|
||||
#include "SettingsUNIX.hxx"
|
||||
#elif defined(WIN32)
|
||||
#include "SettingsWin32.hxx"
|
||||
#else
|
||||
#error Unsupported platform!
|
||||
#endif
|
||||
|
||||
static void cleanup();
|
||||
static bool setupJoystick();
|
||||
static void handleEvents();
|
||||
static uInt32 getTicks();
|
||||
static bool setupProperties(PropertiesSet& set);
|
||||
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
// static uInt32 thePaddleNumber;
|
||||
|
||||
// Lookup table for joystick numbers and events
|
||||
StellaEvent::JoyStick joyList[StellaEvent::LastJSTICK] = {
|
||||
StellaEvent::JSTICK_0, StellaEvent::JSTICK_1, StellaEvent::JSTICK_2,
|
||||
StellaEvent::JSTICK_3, StellaEvent::JSTICK_5, StellaEvent::JSTICK_5
|
||||
};
|
||||
StellaEvent::JoyCode joyButtonList[StellaEvent::LastJCODE] = {
|
||||
StellaEvent::JBUTTON_0, StellaEvent::JBUTTON_1, StellaEvent::JBUTTON_2,
|
||||
StellaEvent::JBUTTON_3, StellaEvent::JBUTTON_4, StellaEvent::JBUTTON_5,
|
||||
StellaEvent::JBUTTON_6, StellaEvent::JBUTTON_7, StellaEvent::JBUTTON_8,
|
||||
StellaEvent::JBUTTON_9, StellaEvent::JBUTTON_10, StellaEvent::JBUTTON_11,
|
||||
StellaEvent::JBUTTON_12, StellaEvent::JBUTTON_13, StellaEvent::JBUTTON_14,
|
||||
StellaEvent::JBUTTON_15, StellaEvent::JBUTTON_16, StellaEvent::JBUTTON_17,
|
||||
StellaEvent::JBUTTON_18, StellaEvent::JBUTTON_19
|
||||
};
|
||||
|
||||
enum JoyType { JT_NONE, JT_REGULAR, JT_STELLADAPTOR_1, JT_STELLADAPTOR_2 };
|
||||
|
||||
struct Stella_Joystick
|
||||
{
|
||||
SDL_Joystick* stick;
|
||||
JoyType type;
|
||||
};
|
||||
|
||||
static Stella_Joystick theJoysticks[StellaEvent::LastJSTICK];
|
||||
|
||||
// Static lookup tables for Stelladaptor axis support
|
||||
static Event::Type SA_Axis[2][2][3] = {
|
||||
Event::JoystickZeroLeft, Event::JoystickZeroRight, Event::PaddleZeroResistance,
|
||||
Event::JoystickZeroUp, Event::JoystickZeroDown, Event::PaddleOneResistance,
|
||||
Event::JoystickOneLeft, Event::JoystickOneRight, Event::PaddleTwoResistance,
|
||||
Event::JoystickOneUp, Event::JoystickOneDown, Event::PaddleThreeResistance
|
||||
};
|
||||
#endif
|
||||
|
||||
// Pointer to the console object or the null pointer
|
||||
static Console* theConsole = (Console*) NULL;
|
||||
|
||||
// Pointer to the display object or the null pointer
|
||||
static FrameBufferSDL* theDisplay = (FrameBufferSDL*) NULL;
|
||||
|
||||
// Pointer to the sound object or the null pointer
|
||||
static Sound* theSound = (Sound*) NULL;
|
||||
|
||||
// Pointer to the settings object or the null pointer
|
||||
static Settings* theSettings = (Settings*) NULL;
|
||||
|
||||
// Indicates if the mouse should be grabbed
|
||||
static bool theGrabMouseIndicator = false;
|
||||
|
||||
// Indicates if the mouse cursor should be hidden
|
||||
static bool theHideCursorIndicator = false;
|
||||
|
||||
// Indicates the current paddle mode
|
||||
static Int32 thePaddleMode;
|
||||
|
||||
// Indicates relative mouse position horizontally
|
||||
static Int32 mouseX = 0;
|
||||
|
||||
// Indicates whether to show information during program execution
|
||||
static bool theShowInfoFlag;
|
||||
|
||||
struct Switches
|
||||
{
|
||||
SDLKey scanCode;
|
||||
StellaEvent::KeyCode keyCode;
|
||||
};
|
||||
|
||||
// Place the most used keys first to speed up access
|
||||
// Todo - initialize this array in the same order as the SDLK
|
||||
// keys are defined, so it can be a constant-time LUT
|
||||
static Switches keyList[] = {
|
||||
{ SDLK_F1, StellaEvent::KCODE_F1 },
|
||||
{ SDLK_F2, StellaEvent::KCODE_F2 },
|
||||
{ SDLK_F3, StellaEvent::KCODE_F3 },
|
||||
{ SDLK_F4, StellaEvent::KCODE_F4 },
|
||||
{ SDLK_F5, StellaEvent::KCODE_F5 },
|
||||
{ SDLK_F6, StellaEvent::KCODE_F6 },
|
||||
{ SDLK_F7, StellaEvent::KCODE_F7 },
|
||||
{ SDLK_F8, StellaEvent::KCODE_F8 },
|
||||
{ SDLK_F9, StellaEvent::KCODE_F9 },
|
||||
{ SDLK_F10, StellaEvent::KCODE_F10 },
|
||||
{ SDLK_F11, StellaEvent::KCODE_F11 },
|
||||
{ SDLK_F12, StellaEvent::KCODE_F12 },
|
||||
{ SDLK_F13, StellaEvent::KCODE_F13 },
|
||||
{ SDLK_F14, StellaEvent::KCODE_F14 },
|
||||
{ SDLK_F15, StellaEvent::KCODE_F15 },
|
||||
|
||||
{ SDLK_UP, StellaEvent::KCODE_UP },
|
||||
{ SDLK_DOWN, StellaEvent::KCODE_DOWN },
|
||||
{ SDLK_LEFT, StellaEvent::KCODE_LEFT },
|
||||
{ SDLK_RIGHT, StellaEvent::KCODE_RIGHT },
|
||||
{ SDLK_SPACE, StellaEvent::KCODE_SPACE },
|
||||
{ SDLK_LCTRL, StellaEvent::KCODE_LCTRL },
|
||||
{ SDLK_RCTRL, StellaEvent::KCODE_RCTRL },
|
||||
{ SDLK_LALT, StellaEvent::KCODE_LALT },
|
||||
{ SDLK_RALT, StellaEvent::KCODE_RALT },
|
||||
{ SDLK_LSUPER, StellaEvent::KCODE_LWIN },
|
||||
{ SDLK_RSUPER, StellaEvent::KCODE_RWIN },
|
||||
{ SDLK_MENU, StellaEvent::KCODE_MENU },
|
||||
|
||||
{ SDLK_a, StellaEvent::KCODE_a },
|
||||
{ SDLK_b, StellaEvent::KCODE_b },
|
||||
{ SDLK_c, StellaEvent::KCODE_c },
|
||||
{ SDLK_d, StellaEvent::KCODE_d },
|
||||
{ SDLK_e, StellaEvent::KCODE_e },
|
||||
{ SDLK_f, StellaEvent::KCODE_f },
|
||||
{ SDLK_g, StellaEvent::KCODE_g },
|
||||
{ SDLK_h, StellaEvent::KCODE_h },
|
||||
{ SDLK_i, StellaEvent::KCODE_i },
|
||||
{ SDLK_j, StellaEvent::KCODE_j },
|
||||
{ SDLK_k, StellaEvent::KCODE_k },
|
||||
{ SDLK_l, StellaEvent::KCODE_l },
|
||||
{ SDLK_m, StellaEvent::KCODE_m },
|
||||
{ SDLK_n, StellaEvent::KCODE_n },
|
||||
{ SDLK_o, StellaEvent::KCODE_o },
|
||||
{ SDLK_p, StellaEvent::KCODE_p },
|
||||
{ SDLK_q, StellaEvent::KCODE_q },
|
||||
{ SDLK_r, StellaEvent::KCODE_r },
|
||||
{ SDLK_s, StellaEvent::KCODE_s },
|
||||
{ SDLK_t, StellaEvent::KCODE_t },
|
||||
{ SDLK_u, StellaEvent::KCODE_u },
|
||||
{ SDLK_v, StellaEvent::KCODE_v },
|
||||
{ SDLK_w, StellaEvent::KCODE_w },
|
||||
{ SDLK_x, StellaEvent::KCODE_x },
|
||||
{ SDLK_y, StellaEvent::KCODE_y },
|
||||
{ SDLK_z, StellaEvent::KCODE_z },
|
||||
|
||||
{ SDLK_0, StellaEvent::KCODE_0 },
|
||||
{ SDLK_1, StellaEvent::KCODE_1 },
|
||||
{ SDLK_2, StellaEvent::KCODE_2 },
|
||||
{ SDLK_3, StellaEvent::KCODE_3 },
|
||||
{ SDLK_4, StellaEvent::KCODE_4 },
|
||||
{ SDLK_5, StellaEvent::KCODE_5 },
|
||||
{ SDLK_6, StellaEvent::KCODE_6 },
|
||||
{ SDLK_7, StellaEvent::KCODE_7 },
|
||||
{ SDLK_8, StellaEvent::KCODE_8 },
|
||||
{ SDLK_9, StellaEvent::KCODE_9 },
|
||||
|
||||
{ SDLK_KP0, StellaEvent::KCODE_KP0 },
|
||||
{ SDLK_KP1, StellaEvent::KCODE_KP1 },
|
||||
{ SDLK_KP2, StellaEvent::KCODE_KP2 },
|
||||
{ SDLK_KP3, StellaEvent::KCODE_KP3 },
|
||||
{ SDLK_KP4, StellaEvent::KCODE_KP4 },
|
||||
{ SDLK_KP5, StellaEvent::KCODE_KP5 },
|
||||
{ SDLK_KP6, StellaEvent::KCODE_KP6 },
|
||||
{ SDLK_KP7, StellaEvent::KCODE_KP7 },
|
||||
{ SDLK_KP8, StellaEvent::KCODE_KP8 },
|
||||
{ SDLK_KP9, StellaEvent::KCODE_KP9 },
|
||||
{ SDLK_KP_PERIOD, StellaEvent::KCODE_KP_PERIOD },
|
||||
{ SDLK_KP_DIVIDE, StellaEvent::KCODE_KP_DIVIDE },
|
||||
{ SDLK_KP_MULTIPLY, StellaEvent::KCODE_KP_MULTIPLY},
|
||||
{ SDLK_KP_MINUS, StellaEvent::KCODE_KP_MINUS },
|
||||
{ SDLK_KP_PLUS, StellaEvent::KCODE_KP_PLUS },
|
||||
{ SDLK_KP_ENTER, StellaEvent::KCODE_KP_ENTER },
|
||||
{ SDLK_KP_EQUALS, StellaEvent::KCODE_KP_EQUALS },
|
||||
|
||||
{ SDLK_BACKSPACE, StellaEvent::KCODE_BACKSPACE },
|
||||
{ SDLK_TAB, StellaEvent::KCODE_TAB },
|
||||
{ SDLK_CLEAR, StellaEvent::KCODE_CLEAR },
|
||||
{ SDLK_RETURN, StellaEvent::KCODE_RETURN },
|
||||
{ SDLK_ESCAPE, StellaEvent::KCODE_ESCAPE },
|
||||
{ SDLK_COMMA, StellaEvent::KCODE_COMMA },
|
||||
{ SDLK_MINUS, StellaEvent::KCODE_MINUS },
|
||||
{ SDLK_PERIOD, StellaEvent::KCODE_PERIOD },
|
||||
{ SDLK_SLASH, StellaEvent::KCODE_SLASH },
|
||||
{ SDLK_BACKSLASH, StellaEvent::KCODE_BACKSLASH },
|
||||
{ SDLK_SEMICOLON, StellaEvent::KCODE_SEMICOLON },
|
||||
{ SDLK_EQUALS, StellaEvent::KCODE_EQUALS },
|
||||
{ SDLK_QUOTE, StellaEvent::KCODE_QUOTE },
|
||||
{ SDLK_BACKQUOTE, StellaEvent::KCODE_BACKQUOTE },
|
||||
{ SDLK_LEFTBRACKET, StellaEvent::KCODE_LEFTBRACKET},
|
||||
{ SDLK_RIGHTBRACKET,StellaEvent::KCODE_RIGHTBRACKET},
|
||||
|
||||
{ SDLK_PRINT, StellaEvent::KCODE_PRTSCREEN },
|
||||
{ SDLK_MODE, StellaEvent::KCODE_SCRLOCK },
|
||||
{ SDLK_PAUSE, StellaEvent::KCODE_PAUSE },
|
||||
{ SDLK_INSERT, StellaEvent::KCODE_INSERT },
|
||||
{ SDLK_HOME, StellaEvent::KCODE_HOME },
|
||||
{ SDLK_PAGEUP, StellaEvent::KCODE_PAGEUP },
|
||||
{ SDLK_DELETE, StellaEvent::KCODE_DELETE },
|
||||
{ SDLK_END, StellaEvent::KCODE_END },
|
||||
{ SDLK_PAGEDOWN, StellaEvent::KCODE_PAGEDOWN }
|
||||
};
|
||||
|
||||
/**
|
||||
Returns number of ticks in microseconds
|
||||
*/
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
inline uInt32 getTicks()
|
||||
{
|
||||
timeval now;
|
||||
gettimeofday(&now, 0);
|
||||
|
||||
return (uInt32) (now.tv_sec * 1000000 + now.tv_usec);
|
||||
}
|
||||
#else
|
||||
inline uInt32 getTicks()
|
||||
{
|
||||
return (uInt32) SDL_GetTicks() * 1000;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
This routine should be called once setupDisplay is called
|
||||
to create the joystick stuff.
|
||||
*/
|
||||
bool setupJoystick()
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
// Keep track of how many Stelladaptors we've found
|
||||
uInt8 saCount = 0;
|
||||
|
||||
// First clear the joystick array
|
||||
for(uInt32 i = 0; i < StellaEvent::LastJSTICK; i++)
|
||||
{
|
||||
theJoysticks[i].stick = (SDL_Joystick*) NULL;
|
||||
theJoysticks[i].type = JT_NONE;
|
||||
}
|
||||
|
||||
// Initialize the joystick subsystem
|
||||
if((SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) || (SDL_NumJoysticks() <= 0))
|
||||
{
|
||||
if(theShowInfoFlag)
|
||||
cout << "No joysticks present, use the keyboard.\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to open 4 regular joysticks and 2 Stelladaptor devices
|
||||
uInt32 limit = SDL_NumJoysticks() <= StellaEvent::LastJSTICK ?
|
||||
SDL_NumJoysticks() : StellaEvent::LastJSTICK;
|
||||
for(uInt32 i = 0; i < limit; i++)
|
||||
{
|
||||
string name = SDL_JoystickName(i);
|
||||
theJoysticks[i].stick = SDL_JoystickOpen(i);
|
||||
|
||||
// Skip if we couldn't open it for any reason
|
||||
if(theJoysticks[i].stick == NULL)
|
||||
continue;
|
||||
|
||||
// Figure out what type of joystick this is
|
||||
if(name.find("Stelladaptor", 0) != string::npos)
|
||||
{
|
||||
saCount++;
|
||||
if(saCount > 2) // Ignore more than 2 Stelladaptors
|
||||
{
|
||||
theJoysticks[i].type = JT_NONE;
|
||||
continue;
|
||||
}
|
||||
else if(saCount == 1)
|
||||
{
|
||||
name = "Left Stelladaptor (Left joystick, Paddles 0 and 1, Left driving controller)";
|
||||
theJoysticks[i].type = JT_STELLADAPTOR_1;
|
||||
}
|
||||
else if(saCount == 2)
|
||||
{
|
||||
name = "Right Stelladaptor (Right joystick, Paddles 2 and 3, Right driving controller)";
|
||||
theJoysticks[i].type = JT_STELLADAPTOR_2;
|
||||
}
|
||||
|
||||
if(theShowInfoFlag)
|
||||
cout << "Joystick " << i << ": " << name << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
theJoysticks[i].type = JT_REGULAR;
|
||||
if(theShowInfoFlag)
|
||||
{
|
||||
cout << "Joystick " << i << ": " << SDL_JoystickName(i)
|
||||
<< " with " << SDL_JoystickNumButtons(theJoysticks[i].stick)
|
||||
<< " buttons.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This routine should be called regularly to handle events
|
||||
*/
|
||||
void handleEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
Uint8 type;
|
||||
SDLKey key;
|
||||
SDLMod mod;
|
||||
|
||||
// Check for an event
|
||||
while(SDL_PollEvent(&event))
|
||||
{
|
||||
// keyboard events
|
||||
if(event.type == SDL_KEYDOWN)
|
||||
{
|
||||
key = event.key.keysym.sym;
|
||||
mod = event.key.keysym.mod;
|
||||
type = event.type;
|
||||
|
||||
// An attempt to speed up event processing
|
||||
// All SDL-specific event actions are accessed by either
|
||||
// Control or Alt keys. So we quickly check for those.
|
||||
if(mod & KMOD_ALT)
|
||||
{
|
||||
if(key == SDLK_EQUALS)
|
||||
theDisplay->resize(1);
|
||||
else if(key == SDLK_MINUS)
|
||||
theDisplay->resize(-1);
|
||||
else if(key == SDLK_RETURN)
|
||||
{
|
||||
theDisplay->toggleFullscreen();
|
||||
}
|
||||
#ifdef DISPLAY_OPENGL
|
||||
else if(key == SDLK_f && theUseOpenGLFlag)
|
||||
((FrameBufferGL*)theDisplay)->toggleFilter();
|
||||
#endif
|
||||
#ifdef DEVELOPER_SUPPORT
|
||||
else if(key == SDLK_END) // Alt-End increases XStart
|
||||
{
|
||||
theConsole->changeXStart(1);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_HOME) // Alt-Home decreases XStart
|
||||
{
|
||||
theConsole->changeXStart(0);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_PAGEUP) // Alt-PageUp increases YStart
|
||||
{
|
||||
theConsole->changeYStart(1);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_PAGEDOWN) // Alt-PageDown decreases YStart
|
||||
{
|
||||
theConsole->changeYStart(0);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(mod & KMOD_CTRL)
|
||||
{
|
||||
if(key == SDLK_g)
|
||||
{
|
||||
// don't change grabmouse in fullscreen mode
|
||||
if(!theDisplay->fullScreen())
|
||||
{
|
||||
theGrabMouseIndicator = !theGrabMouseIndicator;
|
||||
theSettings->setBool("grabmouse", theGrabMouseIndicator);
|
||||
theDisplay->grabMouse(theGrabMouseIndicator);
|
||||
}
|
||||
}
|
||||
else if(key == SDLK_h)
|
||||
{
|
||||
// don't change hidecursor in fullscreen mode
|
||||
if(!theDisplay->fullScreen())
|
||||
{
|
||||
theHideCursorIndicator = !theHideCursorIndicator;
|
||||
theSettings->setBool("hidecursor", theHideCursorIndicator);
|
||||
theDisplay->showCursor(!theHideCursorIndicator);
|
||||
}
|
||||
}
|
||||
#ifdef DEVELOPER_SUPPORT
|
||||
else if(key == SDLK_f) // Ctrl-f toggles NTSC/PAL mode
|
||||
{
|
||||
theConsole->toggleFormat();
|
||||
theDisplay->setupPalette();
|
||||
}
|
||||
else if(key == SDLK_p) // Ctrl-p toggles different palettes
|
||||
{
|
||||
theConsole->togglePalette();
|
||||
theDisplay->setupPalette();
|
||||
}
|
||||
else if(key == SDLK_END) // Ctrl-End increases Width
|
||||
{
|
||||
theConsole->changeWidth(1);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_HOME) // Ctrl-Home decreases Width
|
||||
{
|
||||
theConsole->changeWidth(0);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_PAGEUP) // Ctrl-PageUp increases Height
|
||||
{
|
||||
theConsole->changeHeight(1);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_PAGEDOWN) // Ctrl-PageDown decreases Height
|
||||
{
|
||||
theConsole->changeHeight(0);
|
||||
theDisplay->resize(0);
|
||||
}
|
||||
else if(key == SDLK_s) // Ctrl-s saves properties to a file
|
||||
{
|
||||
if(theConsole->settings().getBool("mergeprops")) // Attempt to merge with propertiesSet
|
||||
{
|
||||
theConsole->saveProperties(theSettings->userPropertiesFilename(), true);
|
||||
}
|
||||
else // Save to file in home directory
|
||||
{
|
||||
string newPropertiesFile = theConsole->settings().baseDir() + "/" + \
|
||||
theConsole->properties().get("Cartridge.Name") + ".pro";
|
||||
replace(newPropertiesFile.begin(), newPropertiesFile.end(), ' ', '_');
|
||||
theConsole->saveProperties(newPropertiesFile);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else // check all the other keys
|
||||
{
|
||||
for(unsigned int i = 0; i < sizeof(keyList) / sizeof(Switches); ++i)
|
||||
{
|
||||
if(keyList[i].scanCode == key)
|
||||
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(event.type == SDL_KEYUP)
|
||||
{
|
||||
key = event.key.keysym.sym;
|
||||
type = event.type;
|
||||
|
||||
for(unsigned int i = 0; i < sizeof(keyList) / sizeof(Switches); ++i)
|
||||
{
|
||||
if(keyList[i].scanCode == key)
|
||||
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, 0);
|
||||
}
|
||||
}
|
||||
else if(event.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
Int32 resistance;
|
||||
uInt32 zoom = theDisplay->zoomLevel();
|
||||
Int32 width = theDisplay->width() * zoom;
|
||||
Event::Type type = Event::NoType;
|
||||
|
||||
// Grabmouse and hidecursor introduce some lag into the mouse movement,
|
||||
// so we need to fudge the numbers a bit
|
||||
if(theGrabMouseIndicator && theHideCursorIndicator)
|
||||
{
|
||||
mouseX = (int)((float)mouseX + (float)event.motion.xrel
|
||||
* 1.5 * (float) zoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseX = mouseX + event.motion.xrel * zoom;
|
||||
}
|
||||
|
||||
// Check to make sure mouseX is within the game window
|
||||
if(mouseX < 0)
|
||||
mouseX = 0;
|
||||
else if(mouseX > width)
|
||||
mouseX = width;
|
||||
|
||||
resistance = (Int32)(1000000.0 * (width - mouseX) / width);
|
||||
|
||||
// Now, set the event of the correct paddle to the calculated resistance
|
||||
if(thePaddleMode == 0)
|
||||
type = Event::PaddleZeroResistance;
|
||||
else if(thePaddleMode == 1)
|
||||
type = Event::PaddleOneResistance;
|
||||
else if(thePaddleMode == 2)
|
||||
type = Event::PaddleTwoResistance;
|
||||
else if(thePaddleMode == 3)
|
||||
type = Event::PaddleThreeResistance;
|
||||
|
||||
theConsole->eventHandler().sendEvent(type, resistance);
|
||||
}
|
||||
else if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
|
||||
{
|
||||
Event::Type type = Event::LastType;
|
||||
Int32 value;
|
||||
|
||||
if(event.type == SDL_MOUSEBUTTONDOWN)
|
||||
value = 1;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
if(thePaddleMode == 0)
|
||||
type = Event::PaddleZeroFire;
|
||||
else if(thePaddleMode == 1)
|
||||
type = Event::PaddleOneFire;
|
||||
else if(thePaddleMode == 2)
|
||||
type = Event::PaddleTwoFire;
|
||||
else if(thePaddleMode == 3)
|
||||
type = Event::PaddleThreeFire;
|
||||
|
||||
theConsole->eventHandler().sendEvent(type, value);
|
||||
}
|
||||
else if(event.type == SDL_ACTIVEEVENT)
|
||||
{
|
||||
if((event.active.state & SDL_APPACTIVE) && (event.active.gain == 0))
|
||||
{
|
||||
if(!theConsole->eventHandler().doPause())
|
||||
{
|
||||
theConsole->eventHandler().sendEvent(Event::Pause, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(event.type == SDL_QUIT)
|
||||
{
|
||||
theConsole->eventHandler().sendEvent(Event::Quit, 1);
|
||||
}
|
||||
else if(event.type == SDL_VIDEOEXPOSE)
|
||||
{
|
||||
theDisplay->refresh();
|
||||
}
|
||||
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
// Read joystick events and modify event states
|
||||
StellaEvent::JoyStick stick;
|
||||
StellaEvent::JoyCode code;
|
||||
Int32 state;
|
||||
Uint8 axis;
|
||||
Uint8 button;
|
||||
Int32 resistance;
|
||||
Sint16 value;
|
||||
JoyType type;
|
||||
|
||||
if(event.jbutton.which >= StellaEvent::LastJSTICK)
|
||||
return;
|
||||
|
||||
stick = joyList[event.jbutton.which];
|
||||
type = theJoysticks[event.jbutton.which].type;
|
||||
|
||||
// Figure put what type of joystick we're dealing with
|
||||
// Stelladaptors behave differently, and can't be remapped
|
||||
switch(type)
|
||||
{
|
||||
case JT_NONE:
|
||||
break;
|
||||
|
||||
case JT_REGULAR:
|
||||
|
||||
if((event.type == SDL_JOYBUTTONDOWN) || (event.type == SDL_JOYBUTTONUP))
|
||||
{
|
||||
if(event.jbutton.button >= StellaEvent::LastJCODE)
|
||||
return;
|
||||
|
||||
code = joyButtonList[event.jbutton.button];
|
||||
state = event.jbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
theConsole->eventHandler().sendJoyEvent(stick, code, state);
|
||||
}
|
||||
else if(event.type == SDL_JOYAXISMOTION)
|
||||
{
|
||||
axis = event.jaxis.axis;
|
||||
value = event.jaxis.value;
|
||||
|
||||
if(axis == 0) // x-axis
|
||||
{
|
||||
theConsole->eventHandler().sendJoyEvent(stick, StellaEvent::JAXIS_LEFT,
|
||||
(value < -16384) ? 1 : 0);
|
||||
theConsole->eventHandler().sendJoyEvent(stick, StellaEvent::JAXIS_RIGHT,
|
||||
(value > 16384) ? 1 : 0);
|
||||
}
|
||||
else if(axis == 1) // y-axis
|
||||
{
|
||||
theConsole->eventHandler().sendJoyEvent(stick, StellaEvent::JAXIS_UP,
|
||||
(value < -16384) ? 1 : 0);
|
||||
theConsole->eventHandler().sendJoyEvent(stick, StellaEvent::JAXIS_DOWN,
|
||||
(value > 16384) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
break; // Regular joystick
|
||||
|
||||
case JT_STELLADAPTOR_1:
|
||||
case JT_STELLADAPTOR_2:
|
||||
|
||||
if((event.type == SDL_JOYBUTTONDOWN) || (event.type == SDL_JOYBUTTONUP))
|
||||
{
|
||||
button = event.jbutton.button;
|
||||
state = event.jbutton.state == SDL_PRESSED ? 1 : 0;
|
||||
|
||||
// Send button events for the joysticks/paddles
|
||||
if(button == 0)
|
||||
{
|
||||
if(type == JT_STELLADAPTOR_1)
|
||||
{
|
||||
theConsole->eventHandler().sendEvent(Event::JoystickZeroFire, state);
|
||||
theConsole->eventHandler().sendEvent(Event::PaddleZeroFire, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
theConsole->eventHandler().sendEvent(Event::JoystickOneFire, state);
|
||||
theConsole->eventHandler().sendEvent(Event::PaddleTwoFire, state);
|
||||
}
|
||||
}
|
||||
else if(button == 1)
|
||||
{
|
||||
if(type == JT_STELLADAPTOR_1)
|
||||
theConsole->eventHandler().sendEvent(Event::PaddleOneFire, state);
|
||||
else
|
||||
theConsole->eventHandler().sendEvent(Event::PaddleThreeFire, state);
|
||||
}
|
||||
}
|
||||
else if(event.type == SDL_JOYAXISMOTION)
|
||||
{
|
||||
axis = event.jaxis.axis;
|
||||
value = event.jaxis.value;
|
||||
|
||||
// Send axis events for the joysticks
|
||||
theConsole->eventHandler().sendEvent(SA_Axis[type-2][axis][0],
|
||||
(value < -16384) ? 1 : 0);
|
||||
theConsole->eventHandler().sendEvent(SA_Axis[type-2][axis][1],
|
||||
(value > 16384) ? 1 : 0);
|
||||
|
||||
// Send axis events for the paddles
|
||||
resistance = (Int32) (1000000.0 * (32767 - value) / 65534);
|
||||
theConsole->eventHandler().sendEvent(SA_Axis[type-2][axis][2], resistance);
|
||||
}
|
||||
break; // Stelladaptor joystick
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Setup the properties set by first checking for a user file
|
||||
"$HOME/.stella/stella.pro", then a system-wide file "/etc/stella.pro".
|
||||
Return false if neither file is found, else return true.
|
||||
|
||||
@param set The properties set to setup
|
||||
*/
|
||||
bool setupProperties(PropertiesSet& set)
|
||||
{
|
||||
bool useMemList = false;
|
||||
string theAlternateProFile = theSettings->getString("altpro");
|
||||
string theUserProFile = theSettings->userPropertiesFilename();
|
||||
string theSystemProFile = theSettings->systemPropertiesFilename();
|
||||
|
||||
#ifdef DEVELOPER_SUPPORT
|
||||
// If the user wishes to merge any property modifications to the
|
||||
// PropertiesSet file, then the PropertiesSet file MUST be loaded
|
||||
// into memory.
|
||||
useMemList = theSettings->getBool("mergeprops");
|
||||
#endif
|
||||
|
||||
// Check to see if the user has specified an alternate .pro file.
|
||||
|
||||
if(theAlternateProFile != "")
|
||||
{
|
||||
set.load(theAlternateProFile, &Console::defaultProperties(), useMemList);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(theUserProFile != "")
|
||||
{
|
||||
set.load(theUserProFile, &Console::defaultProperties(), useMemList);
|
||||
return true;
|
||||
}
|
||||
else if(theSystemProFile != "")
|
||||
{
|
||||
set.load(theSystemProFile, &Console::defaultProperties(), useMemList);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
set.load("", &Console::defaultProperties(), false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Does general cleanup in case any operation failed (or at end of program).
|
||||
*/
|
||||
void cleanup()
|
||||
{
|
||||
#ifdef JOYSTICK_SUPPORT
|
||||
for(uInt32 i = 0; i < StellaEvent::LastJSTICK; i++)
|
||||
{
|
||||
if(SDL_JoystickOpened(i))
|
||||
SDL_JoystickClose(theJoysticks[i].stick);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(theSettings)
|
||||
delete theSettings;
|
||||
|
||||
if(theConsole)
|
||||
delete theConsole;
|
||||
|
||||
if(theSound)
|
||||
delete theSound;
|
||||
|
||||
if(theDisplay)
|
||||
delete theDisplay;
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#if defined(UNIX)
|
||||
theSettings = new SettingsUNIX();
|
||||
#elif defined(WIN32)
|
||||
theSettings = new SettingsWin32();
|
||||
#else
|
||||
#error Unsupported platform!
|
||||
#endif
|
||||
if(!theSettings)
|
||||
{
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
theSettings->loadConfig();
|
||||
|
||||
// Take care of commandline arguments
|
||||
if(!theSettings->loadCommandLine(argc, argv))
|
||||
{
|
||||
string message = "Stella version 1.4_cvs\n\nUsage: stella [options ...] romfile";
|
||||
theSettings->usage(message);
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Cache some settings so they don't have to be repeatedly searched for
|
||||
thePaddleMode = theSettings->getInt("paddle");
|
||||
theShowInfoFlag = theSettings->getBool("showinfo");
|
||||
theGrabMouseIndicator = theSettings->getBool("grabmouse");
|
||||
theHideCursorIndicator = theSettings->getBool("hidecursor");
|
||||
|
||||
// Request that the SDL window be centered, if possible
|
||||
putenv("SDL_VIDEO_CENTERED=1");
|
||||
|
||||
// Get a pointer to the file which contains the cartridge ROM
|
||||
const char* file = argv[argc - 1];
|
||||
|
||||
// Open the cartridge image and read it in
|
||||
ifstream in(file, ios_base::binary);
|
||||
if(!in)
|
||||
{
|
||||
cerr << "ERROR: Couldn't open " << file << "..." << endl;
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uInt8* image = new uInt8[512 * 1024];
|
||||
in.read((char*)image, 512 * 1024);
|
||||
uInt32 size = in.gcount();
|
||||
in.close();
|
||||
|
||||
// Create a properties set for us to use and set it up
|
||||
PropertiesSet propertiesSet;
|
||||
if(!setupProperties(propertiesSet))
|
||||
{
|
||||
delete[] image;
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create an SDL window
|
||||
string videodriver = theSettings->getString("video");
|
||||
if(videodriver == "soft")
|
||||
{
|
||||
theDisplay = new FrameBufferSoft();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using software mode for video.\n";
|
||||
}
|
||||
#ifdef DISPLAY_OPENGL
|
||||
else if(videodriver == "gl")
|
||||
{
|
||||
theDisplay = new FrameBufferGL();
|
||||
theUseOpenGLFlag = true;
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using OpenGL mode for video.\n";
|
||||
}
|
||||
#endif
|
||||
else // a driver that doesn't exist was requested, so use software mode
|
||||
{
|
||||
theDisplay = new FrameBufferSoft();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Using software mode for video.\n";
|
||||
}
|
||||
|
||||
if(!theDisplay)
|
||||
{
|
||||
cerr << "ERROR: Couldn't set up display.\n";
|
||||
delete[] image;
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a sound object for playing audio
|
||||
if(theSettings->getBool("sound"))
|
||||
{
|
||||
uInt32 fragsize = theSettings->getInt("fragsize");
|
||||
uInt32 bufsize = theSettings->getInt("bufsize");
|
||||
theSound = new SoundSDL(fragsize, bufsize);
|
||||
if(theShowInfoFlag)
|
||||
{
|
||||
cout << "Sound enabled, using fragment size = " << fragsize;
|
||||
cout << " and buffer size = " << bufsize << "." << endl;
|
||||
}
|
||||
}
|
||||
else // even if sound has been disabled, we still need a sound object
|
||||
{
|
||||
theSound = new Sound();
|
||||
if(theShowInfoFlag)
|
||||
cout << "Sound disabled.\n";
|
||||
}
|
||||
theSound->setVolume(theSettings->getInt("volume"));
|
||||
|
||||
// Get just the filename of the file containing the ROM image
|
||||
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
|
||||
|
||||
// Create the 2600 game console
|
||||
theConsole = new Console(image, size, filename, *theSettings, propertiesSet,
|
||||
*theDisplay, *theSound);
|
||||
|
||||
// Free the image since we don't need it any longer
|
||||
delete[] image;
|
||||
|
||||
// Setup the SDL joysticks
|
||||
// This must be done after the console is created
|
||||
if(!setupJoystick())
|
||||
{
|
||||
cerr << "ERROR: Couldn't set up joysticks.\n";
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These variables are common to both timing options
|
||||
// and are needed to calculate the overall frames per second.
|
||||
uInt32 frameTime = 0, numberOfFrames = 0;
|
||||
|
||||
if(theSettings->getBool("accurate")) // normal, CPU-intensive timing
|
||||
{
|
||||
// Set up accurate timing stuff
|
||||
uInt32 startTime, delta;
|
||||
uInt32 timePerFrame = (uInt32)(1000000.0 / (double)theSettings->getInt("framerate"));
|
||||
|
||||
// Set the base for the timers
|
||||
frameTime = 0;
|
||||
|
||||
// Main game loop
|
||||
for(;;)
|
||||
{
|
||||
// Exit if the user wants to quit
|
||||
if(theConsole->eventHandler().doQuit())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
startTime = getTicks();
|
||||
handleEvents();
|
||||
theConsole->update();
|
||||
|
||||
// Now, waste time if we need to so that we are at the desired frame rate
|
||||
for(;;)
|
||||
{
|
||||
delta = getTicks() - startTime;
|
||||
|
||||
if(delta >= timePerFrame)
|
||||
break;
|
||||
}
|
||||
|
||||
frameTime += getTicks() - startTime;
|
||||
++numberOfFrames;
|
||||
}
|
||||
}
|
||||
else // less accurate, less CPU-intensive timing
|
||||
{
|
||||
// Set up less accurate timing stuff
|
||||
uInt32 startTime, virtualTime, currentTime;
|
||||
uInt32 timePerFrame = (uInt32)(1000000.0 / (double)theSettings->getInt("framerate"));
|
||||
|
||||
// Set the base for the timers
|
||||
virtualTime = getTicks();
|
||||
frameTime = 0;
|
||||
|
||||
// Main game loop
|
||||
for(;;)
|
||||
{
|
||||
// Exit if the user wants to quit
|
||||
if(theConsole->eventHandler().doQuit())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
startTime = getTicks();
|
||||
handleEvents();
|
||||
theConsole->update();
|
||||
|
||||
currentTime = getTicks();
|
||||
virtualTime += timePerFrame;
|
||||
if(currentTime < virtualTime)
|
||||
{
|
||||
SDL_Delay((virtualTime - currentTime)/1000);
|
||||
}
|
||||
|
||||
currentTime = getTicks() - startTime;
|
||||
frameTime += currentTime;
|
||||
++numberOfFrames;
|
||||
}
|
||||
}
|
||||
|
||||
if(theShowInfoFlag)
|
||||
{
|
||||
double executionTime = (double) frameTime / 1000000.0;
|
||||
double framesPerSecond = (double) numberOfFrames / executionTime;
|
||||
|
||||
cout << endl;
|
||||
cout << numberOfFrames << " total frames drawn\n";
|
||||
cout << framesPerSecond << " frames/second\n";
|
||||
cout << endl;
|
||||
cout << "Cartridge Name: " << theConsole->properties().get("Cartridge.Name");
|
||||
cout << endl;
|
||||
cout << "Cartridge MD5: " << theConsole->properties().get("Cartridge.MD5");
|
||||
cout << endl << endl;
|
||||
}
|
||||
|
||||
// Cleanup time ...
|
||||
cleanup();
|
||||
return 0;
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* XPM */
|
||||
static char * stella_icon[] = {
|
||||
"32 32 3 1",
|
||||
" c None",
|
||||
". c #000000",
|
||||
"+ c #FFFFFF",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" .............. ",
|
||||
" .............. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ....++..++..++.... ",
|
||||
" ....++..++..++.... ",
|
||||
" ....++++..++..++++.... ",
|
||||
" ....++++..++..++++.... ",
|
||||
" ..++++....++....++++.. ",
|
||||
" ..++++....++....++++.. ",
|
||||
" ......++......++......++...... ",
|
||||
" ......++......++......++...... ",
|
||||
" ..++++++.. ..++.. ..++++++.. ",
|
||||
" ..++++++.. ..++.. ..++++++.. ",
|
||||
" ..++++.... ..++.. ....++++.. ",
|
||||
" ..++++.... ..++.. ....++++.. ",
|
||||
" ........ ...... ........ ",
|
||||
" ........ ...... ........ ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
|
@ -1,296 +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-2002 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: SoundALSA.cxx,v 1.6 2003-11-19 15:57:10 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SoundALSA.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundALSA::SoundALSA()
|
||||
: myIsInitializedFlag(false),
|
||||
myPcmHandle(0),
|
||||
myMixerHandle(0),
|
||||
myMixerElem(0),
|
||||
myOriginalVolumeLeft(-1),
|
||||
myOriginalVolumeRight(-1),
|
||||
myBufferSize(0),
|
||||
mySampleRate(0)
|
||||
{
|
||||
Int32 err;
|
||||
char pcmName[] = "plughw:0,0";
|
||||
char mixerName[] = "PCM";
|
||||
char mixerCard[] = "default";
|
||||
|
||||
snd_pcm_hw_params_t* hwparams;
|
||||
|
||||
// Allocate the snd_pcm_hw_params_t structure on the stack
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
|
||||
// Open the PCM device for writing
|
||||
if((err = snd_pcm_open(&myPcmHandle, pcmName, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Init hwparams with full configuration space
|
||||
if((err = snd_pcm_hw_params_any(myPcmHandle, hwparams)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set interleaved access
|
||||
if((err = snd_pcm_hw_params_set_access(myPcmHandle, hwparams,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio data format
|
||||
if((err = snd_pcm_hw_params_set_format(myPcmHandle, hwparams, SND_PCM_FORMAT_U8)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the number of audio channels to 1 (mono mode)
|
||||
if((err = snd_pcm_hw_params_set_channels(myPcmHandle, hwparams, 1)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio sample rate. If the exact rate is not supported by
|
||||
// the hardware, use nearest possible rate
|
||||
mySampleRate = 31400;
|
||||
if((err = snd_pcm_hw_params_set_rate_near(myPcmHandle, hwparams, mySampleRate, 0)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set number of fragments to 2
|
||||
if((err = snd_pcm_hw_params_set_periods(myPcmHandle, hwparams, 2, 0)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set size of fragments to 512 bytes
|
||||
myBufferSize = 512;
|
||||
if((err = snd_pcm_hw_params_set_period_size(myPcmHandle, hwparams,
|
||||
myBufferSize, 0)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply HW parameter settings to PCM device
|
||||
if((err = snd_pcm_hw_params(myPcmHandle, hwparams)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Now, open the mixer so we'll be able to change the volume
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
snd_mixer_selem_id_t* mixerID;
|
||||
|
||||
// Allocate simple mixer ID
|
||||
snd_mixer_selem_id_alloca(&mixerID);
|
||||
|
||||
// Sets simple mixer ID and name
|
||||
snd_mixer_selem_id_set_index(mixerID, 0);
|
||||
snd_mixer_selem_id_set_name(mixerID, mixerName);
|
||||
|
||||
// Open the mixer device
|
||||
if((err = snd_mixer_open(&myMixerHandle, 0)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach the mixer to the default sound card
|
||||
if((err = snd_mixer_attach(myMixerHandle, mixerCard)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Register the mixer with the sound system
|
||||
if((err = snd_mixer_selem_register(myMixerHandle, NULL, NULL)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if((err = snd_mixer_load(myMixerHandle)) < 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the mixer element that will be used to control volume
|
||||
if((myMixerElem = snd_mixer_find_selem(myMixerHandle, mixerID)) == 0)
|
||||
{
|
||||
alsaError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the original volume so we can restore it on exit
|
||||
snd_mixer_selem_get_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 0,
|
||||
&myOriginalVolumeLeft);
|
||||
snd_mixer_selem_get_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 1,
|
||||
&myOriginalVolumeRight);
|
||||
|
||||
// Prepare the audio device for playback
|
||||
snd_pcm_prepare(myPcmHandle);
|
||||
|
||||
// Indicate that the sound system is fully initialized
|
||||
myIsInitializedFlag = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundALSA::~SoundALSA()
|
||||
{
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundALSA::closeDevice()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
// Restore original volume
|
||||
if(myMixerHandle)
|
||||
{
|
||||
if((myOriginalVolumeLeft != -1) && (myOriginalVolumeRight != -1))
|
||||
{
|
||||
snd_mixer_selem_set_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 0,
|
||||
myOriginalVolumeLeft);
|
||||
snd_mixer_selem_set_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 1,
|
||||
myOriginalVolumeRight);
|
||||
}
|
||||
|
||||
snd_mixer_close(myMixerHandle);
|
||||
}
|
||||
|
||||
if(myPcmHandle)
|
||||
snd_pcm_close(myPcmHandle);
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundALSA::getSampleRate() const
|
||||
{
|
||||
return myIsInitializedFlag ? mySampleRate : 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundALSA::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundALSA::setVolume(Int32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag && myMixerElem)
|
||||
{
|
||||
if((percent >= 0) && (percent <= 100))
|
||||
{
|
||||
long int lowerBound, upperBound, newVolume;
|
||||
snd_mixer_selem_get_playback_volume_range(myMixerElem, &lowerBound, &upperBound);
|
||||
|
||||
newVolume = (long int) (((upperBound - lowerBound) * percent / 100.0) + lowerBound);
|
||||
snd_mixer_selem_set_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 0,
|
||||
newVolume);
|
||||
snd_mixer_selem_set_playback_volume(myMixerElem, (_snd_mixer_selem_channel_id) 1,
|
||||
newVolume);
|
||||
}
|
||||
else if(percent == -1) // If -1 has been specified, play sound at default volume
|
||||
{
|
||||
myOriginalVolumeRight = myOriginalVolumeRight = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundALSA::update()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if(myPauseStatus)
|
||||
return;
|
||||
|
||||
snd_pcm_sframes_t frames;
|
||||
uInt8 periodCount = 0;
|
||||
|
||||
// Dequeue samples as long as full fragments are available
|
||||
while(myMediaSource->numberOfAudioSamples() >= myBufferSize)
|
||||
{
|
||||
uInt8 buffer[myBufferSize];
|
||||
myMediaSource->dequeueAudioSamples(buffer, myBufferSize);
|
||||
|
||||
if((frames = snd_pcm_writei(myPcmHandle, buffer, myBufferSize)) == -EPIPE)
|
||||
{
|
||||
snd_pcm_prepare(myPcmHandle);
|
||||
break;
|
||||
}
|
||||
periodCount++;
|
||||
}
|
||||
|
||||
// Fill any unused fragments with silence so that we have a lower
|
||||
// risk of having playback underruns
|
||||
for(int i = 0; i < 1-periodCount; ++i)
|
||||
{
|
||||
frames = snd_pcm_avail_update(myPcmHandle);
|
||||
if (frames > 0)
|
||||
{
|
||||
uInt8 buffer[frames];
|
||||
memset((void*)buffer, 0, frames);
|
||||
snd_pcm_writei(myPcmHandle, buffer, frames);
|
||||
}
|
||||
else if(frames == -EPIPE) // this should never happen
|
||||
{
|
||||
cerr << "EPIPE after write\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundALSA::alsaError(Int32 error)
|
||||
{
|
||||
cerr << "SoundALSA: " << snd_strerror(error) << endl;
|
||||
|
||||
if(myMixerHandle)
|
||||
snd_mixer_close(myMixerHandle);
|
||||
if(myPcmHandle)
|
||||
snd_pcm_close(myPcmHandle);
|
||||
|
||||
mySampleRate = 0;
|
||||
}
|
|
@ -1,114 +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-2002 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: SoundALSA.hxx,v 1.6 2003-11-19 15:57:11 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDALSA_HXX
|
||||
#define SOUNDALSA_HXX
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include "Sound.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements a sound class using the
|
||||
Advanced Linux Sound Architecture (ALSA) version 0.9.x API.
|
||||
|
||||
@author Stephen Anthony
|
||||
@version $Id: SoundALSA.hxx,v 1.6 2003-11-19 15:57:11 stephena Exp $
|
||||
*/
|
||||
class SoundALSA : public Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundALSA();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundALSA();
|
||||
|
||||
public:
|
||||
/**
|
||||
Closes the sound device
|
||||
*/
|
||||
void closeDevice();
|
||||
|
||||
/**
|
||||
Return the playback sample rate for the sound device.
|
||||
|
||||
@return The playback sample rate
|
||||
*/
|
||||
uInt32 getSampleRate() const;
|
||||
|
||||
/**
|
||||
Return true iff the sound device was successfully initlaized.
|
||||
|
||||
@return true iff the sound device was successfully initlaized.
|
||||
*/
|
||||
bool isSuccessfullyInitialized() const;
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a percentage from 0 to 100. A -1 indicates
|
||||
that the volume shouldn't be changed at all.
|
||||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setVolume(Int32 percent);
|
||||
|
||||
/**
|
||||
Update the sound device using the audio sample from the
|
||||
media source.
|
||||
*/
|
||||
void update();
|
||||
|
||||
private:
|
||||
/**
|
||||
Prints the given error message, and frees any resources used.
|
||||
*/
|
||||
void alsaError(Int32 error);
|
||||
|
||||
private:
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// Handle for the PCM device
|
||||
snd_pcm_t* myPcmHandle;
|
||||
|
||||
// Handle for the mixer device
|
||||
snd_mixer_t* myMixerHandle;
|
||||
|
||||
// Mixer elem, used to set volume
|
||||
snd_mixer_elem_t* myMixerElem;
|
||||
|
||||
// Original mixer volume when the sound device was opened
|
||||
long int myOriginalVolumeLeft;
|
||||
long int myOriginalVolumeRight;
|
||||
|
||||
// PCM buffer size
|
||||
uInt32 myBufferSize;
|
||||
|
||||
// PCM sample rate
|
||||
uInt32 mySampleRate;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,240 +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-2002 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: SoundOSS.cxx,v 1.5 2003-11-19 15:57:11 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#define DSP_DEVICE "/dev/dsp"
|
||||
#define MIXER_DEVICE "/dev/mixer"
|
||||
|
||||
#include "SoundOSS.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundOSS::SoundOSS()
|
||||
: myIsInitializedFlag(false),
|
||||
myDspFd(-1),
|
||||
myMixerFd(-1),
|
||||
myOriginalVolume(-1),
|
||||
mySampleRate(0)
|
||||
{
|
||||
// Open the sound device for writing
|
||||
if((myDspFd = open(DSP_DEVICE, O_WRONLY, 0)) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the number and size of fragments
|
||||
int numberAndSizeOfFragments = 0x00020009;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SETFRAGMENT, &numberAndSizeOfFragments) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio data format
|
||||
int format = AFMT_U8;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SETFMT, &format) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the U8 format was selected
|
||||
if(format != AFMT_U8)
|
||||
{
|
||||
cerr << DSP_DEVICE << ": Doesn't support 8-bit sample format!" << endl;
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the number of audio channels to 1 (mono mode)
|
||||
int channels = 1;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_CHANNELS, &channels) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure mono mode was selected
|
||||
if(channels != 1)
|
||||
{
|
||||
cerr << DSP_DEVICE << ": Doesn't support mono mode!" << endl;
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the audio sample rate
|
||||
mySampleRate = 31400;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_SPEED, &mySampleRate) == -1)
|
||||
{
|
||||
perror(DSP_DEVICE);
|
||||
close(myDspFd);
|
||||
myDspFd = -1;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, open the mixer so we'll be able to change the volume
|
||||
if((myMixerFd = open(MIXER_DEVICE, O_RDWR, 0)) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ioctl(myMixerFd, MIXER_READ(SOUND_MIXER_PCM), &myOriginalVolume) == -1)
|
||||
{
|
||||
myOriginalVolume = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Indicate that the sound system is fully initialized
|
||||
myIsInitializedFlag = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundOSS::~SoundOSS()
|
||||
{
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundOSS::closeDevice()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if(myMixerFd != -1)
|
||||
{
|
||||
if(myOriginalVolume != -1)
|
||||
{
|
||||
if(ioctl(myMixerFd, MIXER_WRITE(SOUND_MIXER_PCM),
|
||||
&myOriginalVolume) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
close(myMixerFd);
|
||||
}
|
||||
|
||||
if(myDspFd != -1)
|
||||
{
|
||||
close(myDspFd);
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundOSS::getSampleRate() const
|
||||
{
|
||||
return myIsInitializedFlag ? mySampleRate : 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundOSS::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundOSS::setVolume(Int32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag && (myMixerFd != -1))
|
||||
{
|
||||
if((percent >= 0) && (percent <= 100))
|
||||
{
|
||||
int v = percent | (percent << 8);
|
||||
if(ioctl(myMixerFd, MIXER_WRITE(SOUND_MIXER_PCM), &v) == -1)
|
||||
{
|
||||
perror(MIXER_DEVICE);
|
||||
close(myMixerFd);
|
||||
myMixerFd = -1;
|
||||
}
|
||||
}
|
||||
else if(percent == -1) // If -1 has been specified, play sound at default volume
|
||||
{
|
||||
myOriginalVolume = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundOSS::update()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if(myPauseStatus)
|
||||
return;
|
||||
|
||||
// Get audio buffer information
|
||||
audio_buf_info info;
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Dequeue samples as long as full fragments are available
|
||||
while(myMediaSource->numberOfAudioSamples() >= (uInt32)info.fragsize)
|
||||
{
|
||||
uInt8 buffer[info.fragsize];
|
||||
myMediaSource->dequeueAudioSamples(buffer, (uInt32)info.fragsize);
|
||||
write(myDspFd, buffer, info.fragsize);
|
||||
}
|
||||
|
||||
// Fill any unused fragments with silence so that we have a lower
|
||||
// risk of having playback underruns
|
||||
for(;;)
|
||||
{
|
||||
// Get audio buffer information
|
||||
if(ioctl(myDspFd, SNDCTL_DSP_GETOSPACE, &info) == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(info.fragments > 0)
|
||||
{
|
||||
uInt8 buffer[info.fragsize];
|
||||
memset((void*)buffer, 0, info.fragsize);
|
||||
write(myDspFd, buffer, info.fragsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,97 +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-2002 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: SoundOSS.hxx,v 1.5 2003-11-19 15:57:11 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDOSS_HXX
|
||||
#define SOUNDOSS_HXX
|
||||
|
||||
#include "Sound.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements a sound class using the
|
||||
Open Sound System (OSS) API.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: SoundOSS.hxx,v 1.5 2003-11-19 15:57:11 stephena Exp $
|
||||
*/
|
||||
class SoundOSS : public Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundOSS();
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundOSS();
|
||||
|
||||
public:
|
||||
/**
|
||||
Closes the sound device
|
||||
*/
|
||||
void closeDevice();
|
||||
|
||||
/**
|
||||
Return the playback sample rate for the sound device.
|
||||
|
||||
@return The playback sample rate
|
||||
*/
|
||||
uInt32 getSampleRate() const;
|
||||
|
||||
/**
|
||||
Return true iff the sound device was successfully initlaized.
|
||||
|
||||
@return true iff the sound device was successfully initlaized.
|
||||
*/
|
||||
bool isSuccessfullyInitialized() const;
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a percentage from 0 to 100. A -1 indicates
|
||||
that the volume shouldn't be changed at all.
|
||||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setVolume(Int32 percent);
|
||||
|
||||
/**
|
||||
Update the sound device using the audio sample from the
|
||||
media source.
|
||||
*/
|
||||
void update();
|
||||
|
||||
private:
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// DSP file descriptor
|
||||
int myDspFd;
|
||||
|
||||
// Mixer file descriptor
|
||||
int myMixerFd;
|
||||
|
||||
// Original mixer volume when the sound device was opened
|
||||
int myOriginalVolume;
|
||||
|
||||
// DSP sample rate
|
||||
uInt32 mySampleRate;
|
||||
};
|
||||
#endif
|
|
@ -1,408 +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-2002 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: SoundSDL.cxx,v 1.10 2004-04-27 00:50:52 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "TIASound.h"
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
#include "System.hxx"
|
||||
|
||||
#include "SoundSDL.hxx"
|
||||
|
||||
//#define DIGITAL_SOUND
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize)
|
||||
: myCurrentVolume(SDL_MIX_MAXVOLUME),
|
||||
myFragmentSize(fragsize),
|
||||
myIsInitializedFlag(false),
|
||||
myIsMuted(false),
|
||||
mySampleRate(31400),
|
||||
mySampleQueue(queuesize)
|
||||
{
|
||||
if(1)
|
||||
{
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
cerr << "WARNING: Couldn't initialize SDL audio system! " << endl;
|
||||
cerr << " " << SDL_GetError() << endl;
|
||||
myIsInitializedFlag = false;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_AudioSpec desired;
|
||||
desired.freq = mySampleRate;
|
||||
desired.format = AUDIO_U8;
|
||||
desired.channels = 1;
|
||||
desired.samples = myFragmentSize;
|
||||
desired.callback = callback;
|
||||
desired.userdata = (void*)this;
|
||||
|
||||
if(SDL_OpenAudio(&desired, &myHardwareSpec) < 0)
|
||||
{
|
||||
cerr << "WARNING: Couldn't open SDL audio system! " << endl;
|
||||
cerr << " " << SDL_GetError() << endl;
|
||||
myIsInitializedFlag = false;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the sample buffer isn't to big (if it is the sound code
|
||||
// will not work so we'll need to disable the audio support)
|
||||
if(((float)myHardwareSpec.size / (float)myHardwareSpec.freq) >= 0.25)
|
||||
{
|
||||
cerr << "WARNING: Audio device doesn't support real time audio! Make ";
|
||||
cerr << "sure a sound" << endl;
|
||||
cerr << " server isn't running. Audio is disabled..." << endl;
|
||||
|
||||
SDL_CloseAudio();
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
myIsInitializedFlag = true;
|
||||
myIsMuted = false;
|
||||
mySampleRate = myHardwareSpec.freq;
|
||||
myFragmentSize = myHardwareSpec.samples;
|
||||
|
||||
// cerr << "Freq: " << (int)mySampleRate << endl;
|
||||
// cerr << "Format: " << (int)myHardwareSpec.format << endl;
|
||||
// cerr << "Channels: " << (int)myHardwareSpec.channels << endl;
|
||||
// cerr << "Silence: " << (int)myHardwareSpec.silence << endl;
|
||||
// cerr << "Samples: " << (int)myHardwareSpec.samples << endl;
|
||||
// cerr << "Size: " << (int)myHardwareSpec.size << endl;
|
||||
|
||||
// Now initialize the TIASound object which will actually generate sound
|
||||
Tia_sound_init(31400, mySampleRate);
|
||||
|
||||
// And start the SDL sound subsystem ...
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
myIsInitializedFlag = false;
|
||||
myIsMuted = true;
|
||||
mySampleRate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::~SoundSDL()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
SDL_CloseAudio();
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::mute(bool state)
|
||||
{
|
||||
if(!myIsInitializedFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore multiple calls to do the same thing
|
||||
if(myIsMuted == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myIsMuted = state;
|
||||
|
||||
SDL_PauseAudio(myIsMuted ? 1 : 0);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::setVolume(Int32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if((percent >= 0) && (percent <= 100))
|
||||
{
|
||||
SDL_LockAudio();
|
||||
myCurrentVolume = (uInt32)(((float)percent / 100.0) * SDL_MIX_MAXVOLUME);
|
||||
SDL_UnlockAudio();
|
||||
}
|
||||
else if(percent == -1) // If -1 has been specified, play sound at default volume
|
||||
{
|
||||
myCurrentVolume = SDL_MIX_MAXVOLUME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::update()
|
||||
{
|
||||
#if !defined(DIGITAL_SOUND)
|
||||
if(!myPauseStatus && myIsInitializedFlag)
|
||||
{
|
||||
// Make sure we have exclusive access to the sample queue
|
||||
// SDL_LockAudio();
|
||||
|
||||
// Generate enough samples to keep the sample queue full to capacity
|
||||
uInt32 numbytes = mySampleQueue.capacity() - mySampleQueue.size();
|
||||
uInt8 buffer[numbytes];
|
||||
Tia_process(buffer, numbytes);
|
||||
mySampleQueue.enqueue(buffer, numbytes);
|
||||
|
||||
// Release lock on the sample queue
|
||||
// SDL_UnlockAudio();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::set(uInt16 addr, uInt8 value)
|
||||
{
|
||||
#if defined(DIGITAL_SOUND)
|
||||
// Calculate the number of samples that need to be generated based on the
|
||||
// number of CPU cycles which have passed since the last sound update
|
||||
uInt32 samplesToGenerate =
|
||||
(mySampleRate * (mySystem->cycles() - myLastSoundUpdateCycle)) / 1190000;
|
||||
|
||||
// Update counters and create samples if there's one sample to generate
|
||||
// TODO: This doesn't handle rounding quite right (10/08/2002)
|
||||
if(samplesToGenerate >= 1)
|
||||
{
|
||||
uInt8 buffer[1024];
|
||||
|
||||
for(Int32 sg = (Int32)samplesToGenerate; sg > 0; sg -= 1024)
|
||||
{
|
||||
Tia_process(buffer, ((sg >= 1024) ? 1024 : sg));
|
||||
mySampleQueue.enqueue(buffer, ((sg >= 1024) ? 1024 : sg));
|
||||
}
|
||||
|
||||
myLastSoundUpdateCycle = myLastSoundUpdateCycle +
|
||||
((samplesToGenerate * 1190000) / mySampleRate);
|
||||
}
|
||||
|
||||
if(addr != 0)
|
||||
{
|
||||
Update_tia_sound(addr, value);
|
||||
}
|
||||
#else
|
||||
Update_tia_sound(addr, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL::save(Serializer& out)
|
||||
{
|
||||
string device = "TIASound";
|
||||
|
||||
try
|
||||
{
|
||||
out.putString(device);
|
||||
|
||||
uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0;
|
||||
|
||||
// Only get the TIA sound registers if sound is enabled
|
||||
if(myIsInitializedFlag)
|
||||
Tia_get_registers(®1, ®2, ®3, ®4, ®5, ®6);
|
||||
|
||||
out.putLong(reg1);
|
||||
out.putLong(reg2);
|
||||
out.putLong(reg3);
|
||||
out.putLong(reg4);
|
||||
out.putLong(reg5);
|
||||
out.putLong(reg6);
|
||||
|
||||
out.putLong(myLastSoundUpdateCycle);
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in save state for " << device << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL::load(Deserializer& in)
|
||||
{
|
||||
string device = "TIASound";
|
||||
|
||||
try
|
||||
{
|
||||
if(in.getString() != device)
|
||||
return false;
|
||||
|
||||
uInt8 reg1 = 0, reg2 = 0, reg3 = 0, reg4 = 0, reg5 = 0, reg6 = 0;
|
||||
reg1 = (uInt8) in.getLong();
|
||||
reg2 = (uInt8) in.getLong();
|
||||
reg3 = (uInt8) in.getLong();
|
||||
reg4 = (uInt8) in.getLong();
|
||||
reg5 = (uInt8) in.getLong();
|
||||
reg6 = (uInt8) in.getLong();
|
||||
|
||||
myLastSoundUpdateCycle = (Int32) in.getLong();
|
||||
|
||||
// Only update the TIA sound registers if sound is enabled
|
||||
if(myIsInitializedFlag)
|
||||
Tia_set_registers(reg1, reg2, reg3, reg4, reg5, reg6);
|
||||
}
|
||||
catch(char *msg)
|
||||
{
|
||||
cerr << msg << endl;
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown error in load state for " << device << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::callback(void* udata, uInt8* stream, int len)
|
||||
{
|
||||
SoundSDL* sound = (SoundSDL*)udata;
|
||||
|
||||
if(!sound->isSuccessfullyInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(sound->mySampleQueue.size() > 0)
|
||||
{
|
||||
Int32 offset;
|
||||
uInt8 buffer[2048];
|
||||
for(offset = 0; (offset < len) && (sound->mySampleQueue.size() > 0); )
|
||||
{
|
||||
uInt32 s = sound->mySampleQueue.dequeue(buffer,
|
||||
(2048 > (len - offset) ? (len - offset) : 2048));
|
||||
SDL_MixAudio(stream + offset, buffer, s, sound->myCurrentVolume);
|
||||
offset += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::SampleQueue::SampleQueue(uInt32 capacity)
|
||||
: myCapacity(capacity),
|
||||
myBuffer(0),
|
||||
mySize(0),
|
||||
myHead(0),
|
||||
myTail(0)
|
||||
{
|
||||
myBuffer = new uInt8[myCapacity];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::SampleQueue::~SampleQueue()
|
||||
{
|
||||
delete[] myBuffer;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::SampleQueue::clear()
|
||||
{
|
||||
myHead = myTail = mySize = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL::SampleQueue::dequeue(uInt8* buffer, uInt32 size)
|
||||
{
|
||||
// We can only dequeue up to the number of items in the queue
|
||||
if(size > mySize)
|
||||
{
|
||||
size = mySize;
|
||||
}
|
||||
|
||||
if((myHead + size) < myCapacity)
|
||||
{
|
||||
memcpy((void*)buffer, (const void*)(myBuffer + myHead), size);
|
||||
myHead += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
uInt32 s1 = myCapacity - myHead;
|
||||
uInt32 s2 = size - s1;
|
||||
memcpy((void*)buffer, (const void*)(myBuffer + myHead), s1);
|
||||
memcpy((void*)(buffer + s1), (const void*)myBuffer, s2);
|
||||
myHead = (myHead + size) % myCapacity;
|
||||
}
|
||||
|
||||
mySize -= size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::SampleQueue::enqueue(uInt8* buffer, uInt32 size)
|
||||
{
|
||||
// If an attempt is made to enqueue more than the queue can hold then
|
||||
// we'll only enqueue the last myCapacity elements.
|
||||
if(size > myCapacity)
|
||||
{
|
||||
buffer += (size - myCapacity);
|
||||
size = myCapacity;
|
||||
}
|
||||
|
||||
if((myTail + size) < myCapacity)
|
||||
{
|
||||
memcpy((void*)(myBuffer + myTail), (const void*)buffer, size);
|
||||
myTail += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
uInt32 s1 = myCapacity - myTail;
|
||||
uInt32 s2 = size - s1;
|
||||
memcpy((void*)(myBuffer + myTail), (const void*)buffer, s1);
|
||||
memcpy((void*)myBuffer, (const void*)(buffer + s1), s2);
|
||||
myTail = (myTail + size) % myCapacity;
|
||||
}
|
||||
|
||||
if((mySize + size) > myCapacity)
|
||||
{
|
||||
myHead = (myHead + ((mySize + size) - myCapacity)) % myCapacity;
|
||||
mySize = myCapacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
mySize += size;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundSDL::SampleQueue::size() const
|
||||
{
|
||||
return mySize;
|
||||
}
|
|
@ -1,204 +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-2002 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: SoundSDL.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDSDL_HXX
|
||||
#define SOUNDSDL_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "Sound.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements the sound API for SDL.
|
||||
|
||||
@author Stephen Anthony and Bradford W. Mott
|
||||
@version $Id: SoundSDL.hxx,v 1.7 2004-04-04 02:03:15 stephena Exp $
|
||||
*/
|
||||
class SoundSDL : public Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundSDL(uInt32 fragsize, uInt32 queuesize);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundSDL();
|
||||
|
||||
public:
|
||||
/**
|
||||
Closes the sound device
|
||||
*/
|
||||
void closeDevice();
|
||||
|
||||
/**
|
||||
Return the playback sample rate for the sound device.
|
||||
|
||||
@return The playback sample rate
|
||||
*/
|
||||
uInt32 getSampleRate() const;
|
||||
|
||||
/**
|
||||
Return true iff the sound device was successfully initialized.
|
||||
|
||||
@return true iff the sound device was successfully initialized
|
||||
*/
|
||||
bool isSuccessfullyInitialized() const;
|
||||
|
||||
/**
|
||||
Set the mute state of the sound object.
|
||||
|
||||
@param state Mutes sound if true, unmute if false
|
||||
*/
|
||||
void mute(bool state);
|
||||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a percentage from 0 to 100. A -1 indicates
|
||||
that the volume shouldn't be changed at all.
|
||||
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setVolume(Int32 percent);
|
||||
|
||||
/**
|
||||
Generates audio samples to fill the sample queue.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
Sets the sound register to a given value.
|
||||
|
||||
@param addr The register address
|
||||
@param value The value to save into the register
|
||||
*/
|
||||
void set(uInt16 addr, uInt8 value);
|
||||
|
||||
/**
|
||||
Saves the current state of this device to the given Serializer.
|
||||
|
||||
@param out The serializer device to save to.
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
bool save(Serializer& out);
|
||||
|
||||
/**
|
||||
Loads the current state of this device from the given Deserializer.
|
||||
|
||||
@param in The deserializer device to load from.
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
bool load(Deserializer& in);
|
||||
|
||||
private:
|
||||
/**
|
||||
A bounded queue class used to hold audio samples after they are
|
||||
produced by the MediaSource.
|
||||
*/
|
||||
class SampleQueue
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new SampleQueue instance which can hold the specified
|
||||
number of samples. If the queue ever reaches its capacity then
|
||||
older samples are discarded.
|
||||
*/
|
||||
SampleQueue(uInt32 capacity);
|
||||
|
||||
/**
|
||||
Destroy this SampleQueue instance.
|
||||
*/
|
||||
virtual ~SampleQueue();
|
||||
|
||||
public:
|
||||
/**
|
||||
Clear any samples stored in the queue.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
Dequeue the upto the specified number of samples and store them
|
||||
in the buffer. Returns the actual number of samples removed from
|
||||
the queue.
|
||||
|
||||
@return the actual number of samples removed from the queue.
|
||||
*/
|
||||
uInt32 dequeue(uInt8* buffer, uInt32 size);
|
||||
|
||||
/**
|
||||
Enqueue the specified number of samples from the buffer.
|
||||
*/
|
||||
void enqueue(uInt8* buffer, uInt32 size);
|
||||
|
||||
/**
|
||||
Answers the number of samples currently in the queue.
|
||||
|
||||
@return The number of samples in the queue.
|
||||
*/
|
||||
uInt32 size() const;
|
||||
|
||||
/**
|
||||
Answers the maximum number of samples the queue can hold.
|
||||
|
||||
@return The maximum number of samples in the queue.
|
||||
*/
|
||||
uInt32 capacity() const { return myCapacity; }
|
||||
|
||||
private:
|
||||
const uInt32 myCapacity;
|
||||
uInt8* myBuffer;
|
||||
uInt32 mySize;
|
||||
uInt32 myHead;
|
||||
uInt32 myTail;
|
||||
};
|
||||
|
||||
private:
|
||||
// Current volume
|
||||
uInt32 myCurrentVolume;
|
||||
|
||||
// SDL fragment size
|
||||
uInt32 myFragmentSize;
|
||||
|
||||
// Audio specification structure
|
||||
SDL_AudioSpec myHardwareSpec;
|
||||
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// Indicates if the sound is currently muted
|
||||
bool myIsMuted;
|
||||
|
||||
// DSP sample rate
|
||||
uInt32 mySampleRate;
|
||||
|
||||
// The sample queue size (which is auto-adapting)
|
||||
uInt32 mySampleQueueSize;
|
||||
|
||||
// Queue which holds samples from the media source before they are played
|
||||
SampleQueue mySampleQueue;
|
||||
|
||||
private:
|
||||
// Callback function invoked by the SDL Audio library when it needs data
|
||||
static void callback(void* udata, uInt8* stream, int len);
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue