mirror of https://github.com/stella-emu/stella.git
Reorganized the codebase, since half the stuff here is obsolete.
It's still in the main CVS repository if you want it ... git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@245 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
d9c3b3eb60
commit
469f00eefc
|
@ -0,0 +1,537 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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;
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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.1 2004-05-24 17:18:22 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
|
|
@ -0,0 +1,268 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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.1 2004-05-24 17:18:22 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
|
|
@ -0,0 +1,440 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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;
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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.1 2004-05-24 17:18:22 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
|
|
@ -0,0 +1,188 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-1999 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: Snapshot.cxx,v 1.1 2004-05-24 17:18:22 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;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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
|
|
@ -0,0 +1,334 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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-2004 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.1 2004-05-24 17:18:22 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "TIASound.h"
|
||||
#include "Serializer.hxx"
|
||||
#include "Deserializer.hxx"
|
||||
#include "System.hxx"
|
||||
|
||||
#include "SoundSDL.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::SoundSDL(uInt32 fragsize, uInt32 queuesize)
|
||||
: myCurrentVolume(SDL_MIX_MAXVOLUME),
|
||||
myFragmentSize(fragsize),
|
||||
myIsInitializedFlag(false),
|
||||
myIsMuted(false),
|
||||
mySampleRate(31400),
|
||||
mySampleQueue(queuesize)
|
||||
{
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
cerr << "WARNING: Couldn't initialize SDL audio system! " << endl;
|
||||
cerr << " " << SDL_GetError() << endl;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
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.samples / (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();
|
||||
return;
|
||||
}
|
||||
|
||||
myIsInitializedFlag = true;
|
||||
myIsMuted = false;
|
||||
mySampleRate = myHardwareSpec.freq;
|
||||
myFragmentSize = myHardwareSpec.samples;
|
||||
|
||||
cerr << "Freq: " << (int)myHardwareSpec.freq << 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);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL::~SoundSDL()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
SDL_CloseAudio();
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundSDL::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::mute(bool state)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
// Ignore multiple calls to do the same thing
|
||||
if(myIsMuted == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myIsMuted = state;
|
||||
|
||||
SDL_PauseAudio(myIsMuted ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::setVolume(Int32 percent)
|
||||
{
|
||||
// TODO: Verify that this works...
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundSDL::set(uInt16 addr, uInt8 value)
|
||||
{
|
||||
Update_tia_sound(addr, value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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())
|
||||
{
|
||||
Tia_process(stream, len);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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;
|
||||
}
|
|
@ -13,40 +13,42 @@
|
|||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: SndDOS.hxx,v 1.2 2002-11-13 03:47:55 bwmott Exp $
|
||||
// $Id: SoundSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef SOUNDDOS_HXX
|
||||
#define SOUNDDOS_HXX
|
||||
#ifndef SOUNDSDL_HXX
|
||||
#define SOUNDSDL_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "Sound.hxx"
|
||||
#include "bspf.hxx"
|
||||
#include "MediaSrc.hxx"
|
||||
|
||||
/**
|
||||
This class implements aa sound class for the DOS front-end. It supports
|
||||
SoundBlaster compatible sound cards.
|
||||
This class implements the sound API for SDL.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@version $Id: SndDOS.hxx,v 1.2 2002-11-13 03:47:55 bwmott Exp $
|
||||
@author Stephen Anthony and Bradford W. Mott
|
||||
@version $Id: SoundSDL.hxx,v 1.1 2004-05-24 17:18:22 stephena Exp $
|
||||
*/
|
||||
class SoundDOS
|
||||
class SoundSDL : public Sound
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Create a new sound object
|
||||
*/
|
||||
SoundDOS(bool activate = true);
|
||||
SoundSDL(uInt32 fragsize, uInt32 queuesize);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~SoundDOS();
|
||||
virtual ~SoundSDL();
|
||||
|
||||
public:
|
||||
/**
|
||||
Closes the sound device
|
||||
*/
|
||||
void close();
|
||||
void closeDevice();
|
||||
|
||||
/**
|
||||
Return the playback sample rate for the sound device.
|
||||
|
@ -71,19 +73,41 @@ class SoundDOS
|
|||
|
||||
/**
|
||||
Sets the volume of the sound device to the specified level. The
|
||||
volume is given as a precentage from 0 to 100.
|
||||
volume is given as a percentage from 0 to 100. A -1 indicates
|
||||
that the volume shouldn't be changed at all.
|
||||
|
||||
@param volume The new volume for the sound device
|
||||
@param percent The new volume percentage level for the sound device
|
||||
*/
|
||||
void setSoundVolume(uInt32 volume);
|
||||
void setVolume(Int32 percent);
|
||||
|
||||
/**
|
||||
Update the sound device using the audio sample from the specified
|
||||
media source.
|
||||
|
||||
@param mediaSource The media source to get audio samples from.
|
||||
Generates audio samples to fill the sample queue.
|
||||
*/
|
||||
void updateSound(MediaSource& mediaSource);
|
||||
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:
|
||||
/**
|
||||
|
@ -132,12 +156,19 @@ class SoundDOS
|
|||
*/
|
||||
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;
|
||||
volatile uInt32 mySize;
|
||||
volatile uInt32 myHead;
|
||||
volatile uInt32 myTail;
|
||||
uInt32 mySize;
|
||||
uInt32 myHead;
|
||||
uInt32 myTail;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -147,25 +178,27 @@ class SoundDOS
|
|||
// SDL fragment size
|
||||
uInt32 myFragmentSize;
|
||||
|
||||
// Audio specification structure
|
||||
SDL_AudioSpec myHardwareSpec;
|
||||
|
||||
// Indicates if the sound device was successfully initialized
|
||||
bool myIsInitializedFlag;
|
||||
|
||||
// Mutex
|
||||
bool myUpdateLock;
|
||||
bool myCallbackLock;
|
||||
|
||||
// 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 sound library when it needs data
|
||||
static void callback(void* udata, void* stream, int len);
|
||||
// Callback function invoked by the SDL Audio library when it needs data
|
||||
static void callback(void* udata, uInt8* stream, int len);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,992 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:22 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;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* XPM */
|
||||
static char * stella_icon[] = {
|
||||
"32 32 3 1",
|
||||
" c None",
|
||||
". c #000000",
|
||||
"+ c #FFFFFF",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" .............. ",
|
||||
" .............. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ..++..++..++.. ",
|
||||
" ....++..++..++.... ",
|
||||
" ....++..++..++.... ",
|
||||
" ....++++..++..++++.... ",
|
||||
" ....++++..++..++++.... ",
|
||||
" ..++++....++....++++.. ",
|
||||
" ..++++....++....++++.. ",
|
||||
" ......++......++......++...... ",
|
||||
" ......++......++......++...... ",
|
||||
" ..++++++.. ..++.. ..++++++.. ",
|
||||
" ..++++++.. ..++.. ..++++++.. ",
|
||||
" ..++++.... ..++.. ....++++.. ",
|
||||
" ..++++.... ..++.. ....++++.. ",
|
||||
" ........ ...... ........ ",
|
||||
" ........ ...... ........ ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "};
|
|
@ -1,208 +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: PCJoys.cxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <dos.h>
|
||||
#include <time.h>
|
||||
#include "PCJoys.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PCJoysticks::PCJoysticks(bool useAxisMidpoint)
|
||||
: myGamePort(0x0201),
|
||||
myUseAxisMidpoint(useAxisMidpoint)
|
||||
{
|
||||
for(uInt32 i = 0; i < 4; ++i)
|
||||
{
|
||||
myMinimum[i] = 0x0FFFFFFF;
|
||||
myMaximum[i] = 0;
|
||||
myMidpoint[i] = 0;
|
||||
}
|
||||
|
||||
// Determine which joysticks are present
|
||||
myPresent = detect();
|
||||
|
||||
// If we're using midpoints then calibrate them now
|
||||
if(myUseAxisMidpoint)
|
||||
{
|
||||
calibrate();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PCJoysticks::~PCJoysticks()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PCJoysticks::present() const
|
||||
{
|
||||
return myPresent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PCJoysticks::read(bool button[4], Int16 axis[4])
|
||||
{
|
||||
// Get the state of each of the buttons
|
||||
uInt8 b = (~inportb(myGamePort)) >> 4;
|
||||
button[0] = b & 0x01 ? true : false;
|
||||
button[1] = b & 0x02 ? true : false;
|
||||
button[2] = b & 0x04 ? true : false;
|
||||
button[3] = b & 0x08 ? true : false;
|
||||
|
||||
// Count how long it takes each axis to change states
|
||||
Int32 count[4] = {0, 0, 0, 0};
|
||||
disable();
|
||||
outportb(myGamePort, 0);
|
||||
for(uInt32 counter = 0; counter < 0x000FFFFF; ++counter)
|
||||
{
|
||||
uInt8 i = inportb(myGamePort);
|
||||
|
||||
if(i & 0x01)
|
||||
++count[0];
|
||||
if(i & 0x02)
|
||||
++count[1];
|
||||
if(i & 0x04)
|
||||
++count[2];
|
||||
if(i & 0x08)
|
||||
++count[3];
|
||||
if(!(i & myPresent))
|
||||
break;
|
||||
}
|
||||
enable();
|
||||
|
||||
// Determine the position of each of the axes
|
||||
for(uInt32 t = 0; t < 4; ++t)
|
||||
{
|
||||
// Is this axis being used?
|
||||
if(myPresent & (1 << t))
|
||||
{
|
||||
// Update the maximum for this axis if needed
|
||||
if(count[t] > myMaximum[t])
|
||||
myMaximum[t] = count[t];
|
||||
|
||||
// Update the minimum for this axis if needed
|
||||
if(count[t] < myMinimum[t])
|
||||
myMinimum[t] = count[t];
|
||||
|
||||
// If the minimum and maximum aren't far enough apart then assume 0
|
||||
if(myMaximum[t] - myMinimum[t] < (myMaximum[t] >> 3))
|
||||
{
|
||||
axis[t] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Are we using midpoints?
|
||||
if(myUseAxisMidpoint)
|
||||
{
|
||||
// Yes, so calculate axis value using midpoint
|
||||
if(count[t] < myMidpoint[t])
|
||||
{
|
||||
double n = myMidpoint[t] - count[t];
|
||||
double d = myMidpoint[t] - myMinimum[t];
|
||||
double f = ((d == 0.0) ? 0.0 : (n / d));
|
||||
if(d < (myMaximum[t] >> 3))
|
||||
axis[t] = 0;
|
||||
else
|
||||
axis[t] = (Int16)((Int32)(-32767L * f));
|
||||
}
|
||||
else
|
||||
{
|
||||
double n = count[t] - myMidpoint[t];
|
||||
double d = myMaximum[t] - myMidpoint[t];
|
||||
double f = ((d == 0.0) ? 0.0 : (n / d));
|
||||
if(d < (myMaximum[t] >> 3))
|
||||
axis[t] = 0;
|
||||
else
|
||||
axis[t] = (Int16)((Int32)(32767L * f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No, so calculate axis value without using the midpoint
|
||||
double n = count[t] - myMinimum[t];
|
||||
double d = myMaximum[t] - myMinimum[t];
|
||||
double f = ((d == 0.0) ? 0.5 : (n / d));
|
||||
axis[t] = (Int16)((Int32)(65534L * f) - 32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
axis[t] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 PCJoysticks::detect() const
|
||||
{
|
||||
uInt8 present = 0;
|
||||
|
||||
// Reset the game port bits to 1's
|
||||
outportb(myGamePort, 0);
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
// Wait for low on all four joystick bits or for time to expire
|
||||
do
|
||||
{
|
||||
present = inportb(myGamePort) & 0x0F;
|
||||
}
|
||||
while(((clock() - start) < (CLOCKS_PER_SEC / 2)) && present);
|
||||
|
||||
// Setup joystick present mask that tells which joysticks are present
|
||||
present = (present ^ 0x0F) & 0x0F;
|
||||
present = present & (((present & 0x03) == 0x03) ? 0x0F : 0x0C);
|
||||
present = present & (((present & 0x0C) == 0x0C) ? 0x0F : 0x03);
|
||||
|
||||
return present;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PCJoysticks::calibrate()
|
||||
{
|
||||
// Make sure a joystick is present before we do a lot of work
|
||||
if(present())
|
||||
{
|
||||
// Count how long it takes each axis to change states
|
||||
Int32 count[4] = {0, 0, 0, 0};
|
||||
disable();
|
||||
outportb(myGamePort, 0);
|
||||
for(uInt32 counter = 0; counter < 0x000FFFFF; ++counter)
|
||||
{
|
||||
uInt8 i = inportb(myGamePort);
|
||||
|
||||
if(i & 0x01)
|
||||
++count[0];
|
||||
if(i & 0x02)
|
||||
++count[1];
|
||||
if(i & 0x04)
|
||||
++count[2];
|
||||
if(i & 0x08)
|
||||
++count[3];
|
||||
if(!(i & myPresent))
|
||||
break;
|
||||
}
|
||||
enable();
|
||||
|
||||
for(uInt32 t = 0; t < 4; ++t)
|
||||
{
|
||||
myMidpoint[t] = count[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +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: PCJoys.hxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef PCJOYSTICKS_HXX
|
||||
#define PCJOYSTICKS_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class PCJoysticks
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Constructor
|
||||
|
||||
@param useAxisMidpoint Indicates if a "midpoints" should be used
|
||||
*/
|
||||
PCJoysticks(bool useAxisMidpoint);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
~PCJoysticks();
|
||||
|
||||
public:
|
||||
/**
|
||||
Answers true iff a joystick is connected to the system
|
||||
|
||||
@return true iff a joysticks is connected
|
||||
*/
|
||||
bool present() const;
|
||||
|
||||
/**
|
||||
Read the state of the joystick and update the button and axis arrays
|
||||
|
||||
@param buttons Array which holds the button state upon exit
|
||||
@param axes Array which holds the axis state upon exit
|
||||
*/
|
||||
void read(bool buttons[4], Int16 axes[4]);
|
||||
|
||||
private:
|
||||
// Answers mask that indicates which joysticks are present
|
||||
uInt8 detect() const;
|
||||
|
||||
// Calibrate axes midpoints
|
||||
void calibrate();
|
||||
|
||||
private:
|
||||
uInt8 myPresent;
|
||||
const uInt16 myGamePort;
|
||||
const bool myUseAxisMidpoint;
|
||||
Int32 myMinimum[4];
|
||||
Int32 myMaximum[4];
|
||||
Int32 myMidpoint[4];
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,264 +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-2003 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: SndDOS.cxx,v 1.3 2003-02-17 05:09:21 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include "SndDOS.hxx"
|
||||
#include "dos.h"
|
||||
#include "dos_sb.h"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SoundDOS(bool activate)
|
||||
: myCurrentVolume(100),
|
||||
myFragmentSize(2048),
|
||||
myIsInitializedFlag(false),
|
||||
myUpdateLock(false),
|
||||
myIsMuted(false),
|
||||
mySampleRate(31400),
|
||||
mySampleQueue(mySampleRate)
|
||||
{
|
||||
if(activate)
|
||||
{
|
||||
int bps = 8;
|
||||
int stereo = 0;
|
||||
int buffersize = myFragmentSize;
|
||||
int playback_freq = mySampleRate;
|
||||
|
||||
if(sb_init(&playback_freq, &bps, &buffersize, &stereo) < 0)
|
||||
{
|
||||
cerr << "WARNING: Couldn't initialize audio system! " << endl;
|
||||
myIsInitializedFlag = false;
|
||||
mySampleRate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mySampleRate = playback_freq;
|
||||
myFragmentSize = buffersize;
|
||||
|
||||
myIsInitializedFlag = true;
|
||||
myIsMuted = false;
|
||||
|
||||
// Start playing audio
|
||||
sb_startoutput((sbmix_t)callback, (void*)this);
|
||||
}
|
||||
else
|
||||
{
|
||||
myIsInitializedFlag = false;
|
||||
myIsMuted = true;
|
||||
mySampleRate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::~SoundDOS()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundDOS::getSampleRate() const
|
||||
{
|
||||
return myIsInitializedFlag ? mySampleRate : 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SoundDOS::isSuccessfullyInitialized() const
|
||||
{
|
||||
return myIsInitializedFlag;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::mute(bool state)
|
||||
{
|
||||
if(!myIsInitializedFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore multiple calls to do the same thing
|
||||
if(myIsMuted == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myIsMuted = state;
|
||||
|
||||
if(myIsMuted)
|
||||
{
|
||||
sb_stopoutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_startoutput((sbmix_t)callback, (void*)this);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::close()
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
sb_shutdown();
|
||||
}
|
||||
|
||||
myIsInitializedFlag = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::setSoundVolume(uInt32 percent)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
if((percent >= 0) && (percent <= 100))
|
||||
{
|
||||
// TODO: At some point we should support setting the volume...
|
||||
myCurrentVolume = percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::updateSound(MediaSource& mediaSource)
|
||||
{
|
||||
if(myIsInitializedFlag)
|
||||
{
|
||||
// Move all of the generated samples into our private sample queue
|
||||
uInt8 buffer[4096];
|
||||
while(mediaSource.numberOfAudioSamples() > 0)
|
||||
{
|
||||
uInt32 size = mediaSource.dequeueAudioSamples(buffer, 4096);
|
||||
mySampleQueue.enqueue(buffer, size);
|
||||
}
|
||||
|
||||
// Block until the sound interrupt has consumed all but 142 milliseconds
|
||||
// of the available audio samples
|
||||
uInt32 leave = mySampleRate / 7;
|
||||
while(mySampleQueue.size() > leave)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::callback(void* udata, void* stream, int len)
|
||||
{
|
||||
SoundDOS* sound = (SoundDOS*)udata;
|
||||
|
||||
if(!sound->myIsInitializedFlag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't use samples unless there's at least 100 milliseconds worth of data
|
||||
if(sound->mySampleQueue.size() < (sound->mySampleRate / 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sound->mySampleQueue.dequeue((uInt8*)stream, len);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SampleQueue::SampleQueue(uInt32 capacity)
|
||||
: myCapacity(capacity),
|
||||
myBuffer(0),
|
||||
mySize(0),
|
||||
myHead(0),
|
||||
myTail(0)
|
||||
{
|
||||
myBuffer = new uInt8[myCapacity];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundDOS::SampleQueue::~SampleQueue()
|
||||
{
|
||||
delete[] myBuffer;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SoundDOS::SampleQueue::clear()
|
||||
{
|
||||
myHead = myTail = mySize = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundDOS::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 SoundDOS::SampleQueue::enqueue(uInt8* buffer, uInt32 size)
|
||||
{
|
||||
disable();
|
||||
if((mySize + size) > myCapacity)
|
||||
{
|
||||
size = myCapacity - mySize;
|
||||
}
|
||||
enable();
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
disable();
|
||||
mySize += size;
|
||||
enable();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 SoundDOS::SampleQueue::size() const
|
||||
{
|
||||
return mySize;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of version 2 of the GNU Library General
|
||||
** Public License as published by the Free Software Foundation.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Library General Public License for more details. To obtain a
|
||||
** copy of the GNU Library General Public License, write to the Free
|
||||
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**
|
||||
** Any permitted reproduction of these routines, in whole or in part,
|
||||
** must bear this legend.
|
||||
**
|
||||
** dos_sb.h
|
||||
**
|
||||
** DOS Sound Blaster header file
|
||||
** $Id: dos_sb.h,v 1.1 2002-11-13 03:47:55 bwmott Exp $
|
||||
*/
|
||||
|
||||
#ifndef DOS_SB_H
|
||||
#define DOS_SB_H
|
||||
|
||||
/* Thanks, Allegro! */
|
||||
#define BPS_TO_TIMER(x) (1193182L / (long)(x))
|
||||
#define END_OF_FUNCTION(x) void x##_end(void) {}
|
||||
#define END_OF_STATIC_FUNCTION(x) static void x##_end(void) {}
|
||||
#define LOCK_VARIABLE(x) _go32_dpmi_lock_data((void*)&x, sizeof(x))
|
||||
#define LOCK_FUNCTION(x) _go32_dpmi_lock_code(x, (long)x##_end - (long)x)
|
||||
|
||||
#define DISABLE_INTS() __asm__ __volatile__ ("cli")
|
||||
#define ENABLE_INTS() __asm__ __volatile__ ("sti")
|
||||
|
||||
typedef void (*sbmix_t)(void *userdata, void *buffer, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int sb_init(int *sample_rate, int *bps, int *buf_size, int *stereo);
|
||||
extern void sb_shutdown(void);
|
||||
extern int sb_startoutput(sbmix_t fillbuf, void *userdata);
|
||||
extern void sb_stopoutput(void);
|
||||
extern void sb_setrate(int rate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* DOS_SB_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,132 +0,0 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* LIBRARY Functions - Scan code definitions Copyright K.W 1994 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Title : Keyboard Code Definitions */
|
||||
/* */
|
||||
/* File Name : SCANDEF.H */
|
||||
/* */
|
||||
/* Author : Keith Wilkins */
|
||||
/* */
|
||||
/* Version : 0.01 */
|
||||
/* */
|
||||
/* Desciption : This header file defines all of the scan code definitions */
|
||||
/* */
|
||||
/* Functions : None */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Revision History: */
|
||||
/* */
|
||||
/* Version Date Who Description of changes */
|
||||
/* ------- ---- --- ---------------------- */
|
||||
/* */
|
||||
/* 0.01 13/11/94 K.W Creation */
|
||||
/* */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef SCANDEF_H
|
||||
#define SCANDEF_H
|
||||
|
||||
#define SCAN_BASE (0x00)
|
||||
#define SCAN_PAUSE (0x00) // We'll use 0x00 for the pause code
|
||||
#define SCAN_ESC (0x01)
|
||||
#define SCAN_1 (0x02)
|
||||
#define SCAN_2 (0x03)
|
||||
#define SCAN_3 (0x04)
|
||||
#define SCAN_4 (0x05)
|
||||
#define SCAN_5 (0x06)
|
||||
#define SCAN_6 (0x07)
|
||||
#define SCAN_7 (0x08)
|
||||
#define SCAN_8 (0x09)
|
||||
#define SCAN_9 (0x0a)
|
||||
#define SCAN_0 (0x0b)
|
||||
#define SCAN_MINUS (0x0c)
|
||||
#define SCAN_EQUALS (0x0d)
|
||||
#define SCAN_BSPACE (0x0e)
|
||||
#define SCAN_TAB (0x0f)
|
||||
|
||||
#define SCAN_Q (0x10)
|
||||
#define SCAN_W (0x11)
|
||||
#define SCAN_E (0x12)
|
||||
#define SCAN_R (0x13)
|
||||
#define SCAN_T (0x14)
|
||||
#define SCAN_Y (0x15)
|
||||
#define SCAN_U (0x16)
|
||||
#define SCAN_I (0x17)
|
||||
#define SCAN_O (0x18)
|
||||
#define SCAN_P (0x19)
|
||||
#define SCAN_LSQRB (0x1a)
|
||||
#define SCAN_RSQRB (0x1b)
|
||||
#define SCAN_RETURN (0x1c)
|
||||
#define SCAN_ENTER (0x1c)
|
||||
#define SCAN_CTRL (0x1d)
|
||||
#define SCAN_A (0x1e)
|
||||
#define SCAN_S (0x1f)
|
||||
|
||||
#define SCAN_D (0x20)
|
||||
#define SCAN_F (0x21)
|
||||
#define SCAN_G (0x22)
|
||||
#define SCAN_H (0x23)
|
||||
#define SCAN_J (0x24)
|
||||
#define SCAN_K (0x25)
|
||||
#define SCAN_L (0x26)
|
||||
#define SCAN_SCOLON (0x27)
|
||||
#define SCAN_APSTPY (0x28) // Apostrophy '''''
|
||||
#define SCAN_TILDE (0x29)
|
||||
#define SCAN_LSHIFT (0x2a)
|
||||
#define SCAN_HASH (0x2b)
|
||||
#define SCAN_Z (0x2c)
|
||||
#define SCAN_X (0x2d)
|
||||
#define SCAN_C (0x2e)
|
||||
#define SCAN_V (0x2f)
|
||||
|
||||
#define SCAN_B (0x30)
|
||||
#define SCAN_N (0x31)
|
||||
#define SCAN_M (0x32)
|
||||
#define SCAN_COMMA (0x33)
|
||||
#define SCAN_STOP (0x34)
|
||||
#define SCAN_FSLASH (0x35)
|
||||
#define SCAN_RSHIFT (0x36)
|
||||
#define SCAN_STAR (0x37)
|
||||
#define SCAN_ALT (0x38)
|
||||
#define SCAN_SPACE (0x39)
|
||||
#define SCAN_CAPS (0x3a)
|
||||
#define SCAN_F1 (0x3b)
|
||||
#define SCAN_F2 (0x3c)
|
||||
#define SCAN_F3 (0x3d)
|
||||
#define SCAN_F4 (0x3e)
|
||||
#define SCAN_F5 (0x3f)
|
||||
|
||||
#define SCAN_F6 (0x40)
|
||||
#define SCAN_F7 (0x41)
|
||||
#define SCAN_F8 (0x42)
|
||||
#define SCAN_F9 (0x43)
|
||||
#define SCAN_F10 (0x44)
|
||||
#define SCAN_NUMLCK (0x45)
|
||||
#define SCAN_SCRLCK (0x46)
|
||||
#define SCAN_HOME (0x47)
|
||||
#define SCAN_UP (0x48)
|
||||
#define SCAN_PGUP (0x49)
|
||||
#define SCAN_DASH (0x4a) // Number pad minus
|
||||
#define SCAN_LEFT (0x4b)
|
||||
#define SCAN_CENTRE (0x4c) // Number pad centre
|
||||
#define SCAN_RIGHT (0x4d)
|
||||
#define SCAN_PLUS (0x4e) // Number pad plus
|
||||
#define SCAN_END (0x4f)
|
||||
|
||||
#define SCAN_DOWN (0x50)
|
||||
#define SCAN_PGDN (0x51)
|
||||
#define SCAN_INS (0x52)
|
||||
#define SCAN_DEL (0x53)
|
||||
|
||||
#define SCAN_BSLASH (0x56)
|
||||
#define SCAN_F11 (0x57)
|
||||
#define SCAN_F12 (0x58)
|
||||
|
||||
#endif
|
||||
|
||||
/* END OF SCANDEF.H */
|
|
@ -1,287 +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-2003 by Bradford W. Mott
|
||||
//
|
||||
// See the file "license" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// This code is based on the vga256fb frame buffer device driver for
|
||||
// Linux by Salvatore Sanfilippo <antirez@invece.org>. The vga256fb
|
||||
// code can be found at http://www.kyuzz.org/antirez/vga256fb.htm. It
|
||||
// was released under the GNU General Public License.
|
||||
//
|
||||
// $Id: vga.cxx,v 1.1 2003-02-17 05:17:42 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#include <sys/farptr.h>
|
||||
#include <dos.h>
|
||||
|
||||
#include "vga.hxx"
|
||||
|
||||
// Structure for holding VGA mode information and register settings
|
||||
struct VgaModeInfo
|
||||
{
|
||||
unsigned int xres; // X resolution
|
||||
unsigned int yres; // Y resolution
|
||||
bool chained; // Chained flag
|
||||
unsigned char crt[0x19]; // 24 CRT sub-registers
|
||||
unsigned char attrib[0x15]; // 21 attribute sub-registers
|
||||
unsigned char graphic[0x09]; // 9 graphic sub-registers
|
||||
unsigned char sequencer[0x05]; // 5 sequencer sub-registers
|
||||
unsigned char misc; // misc register
|
||||
};
|
||||
|
||||
// VGA mode information for 320x200x256 colors at 60Hz
|
||||
static VgaModeInfo Vga320x200x60Hz = {
|
||||
xres: 320,
|
||||
yres: 200,
|
||||
chained: true,
|
||||
crt: {
|
||||
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0A, 0x3E,
|
||||
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x84, 0x8F, 0x28, 0x40, 0x90, 0x08, 0xA3 },
|
||||
attrib: {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00, },
|
||||
graphic: {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF },
|
||||
sequencer: {
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E },
|
||||
misc: 0x63
|
||||
};
|
||||
|
||||
// VGA mode information for 320x200x256 colors at 70Hz (standard BIOS 13h mode)
|
||||
static VgaModeInfo Vga320x200x70Hz = {
|
||||
xres: 320,
|
||||
yres: 200,
|
||||
chained: true,
|
||||
crt: {
|
||||
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
|
||||
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x9C, 0x8E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3 },
|
||||
attrib: {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00 },
|
||||
graphic: {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF },
|
||||
sequencer: {
|
||||
0x03, 0x01, 0x0F, 0x00, 0x0E },
|
||||
misc: 0x63
|
||||
};
|
||||
|
||||
// VGA mode information for 320x240x256 colors at 60Hz (square pixels)
|
||||
static VgaModeInfo Vga320x240x60Hz = {
|
||||
xres: 320,
|
||||
yres: 240,
|
||||
chained: false,
|
||||
crt: {
|
||||
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0D, 0x3E,
|
||||
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xEA, 0xAC, 0xDF, 0x28, 0x00, 0xE7, 0x06, 0xE3 },
|
||||
attrib: {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x41, 0x00, 0x0F, 0x00, 0x00, },
|
||||
graphic: {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF },
|
||||
sequencer: {
|
||||
0x03, 0x01, 0x0F, 0x00, 0x06 },
|
||||
misc: 0xE3
|
||||
};
|
||||
|
||||
#define V_CRT_INDEX 0x3D4 // CRT address (index) register
|
||||
#define V_CRT_RW 0x3D5 // CRT data register
|
||||
#define V_ISTAT1_R 0x3DA // Input status register #1
|
||||
#define V_FEATURE_W 0x3DA // Feature control register, (write)
|
||||
#define V_SEQ_INDEX 0x3C4 // Sequencer address (index) register
|
||||
#define V_SEQ_RW 0x3C5 // Sequencer data register
|
||||
#define V_GR_INDEX 0x3CE // VGA address (index) register
|
||||
#define V_GR_RW 0x3CF // VGA data register
|
||||
#define V_MISC_R 0x3CC // VGA misc register (read)
|
||||
#define V_MISC_W 0x3C2 // VGA misc register (write)
|
||||
#define V_ATTR_IW 0x3C0 // Attribute index and data register (write)
|
||||
#define V_ATTR_R 0x3C1 // Attribute data register (read)
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline void put_sequence(int i, unsigned char b)
|
||||
{
|
||||
outportb(V_SEQ_INDEX, i);
|
||||
outportb(V_SEQ_RW, b);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline void put_graph(int i, unsigned char b)
|
||||
{
|
||||
outportb(V_GR_INDEX, i);
|
||||
outportb(V_GR_RW, b);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline void put_misc(unsigned char b)
|
||||
{
|
||||
outportb(V_MISC_W, b);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline void put_attr(int i, unsigned char b)
|
||||
{
|
||||
// Warning: as you can see the 0x20 bit will be set to zero
|
||||
// so the video output will be disabled, if you want read or write
|
||||
// (since some VGA cards allows you to write without setting the PAS
|
||||
// bit) without put the video off OR the index with 0x20 */
|
||||
|
||||
// reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
|
||||
// set the index
|
||||
outportb(V_ATTR_IW, i);
|
||||
|
||||
// write data
|
||||
outportb(V_ATTR_IW, b);
|
||||
|
||||
// reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline void put_crt(int i, unsigned char b)
|
||||
{
|
||||
outportb(V_CRT_INDEX, i);
|
||||
outportb(V_CRT_RW, b);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static inline unsigned char get_crt(int i)
|
||||
{
|
||||
outportb(V_CRT_INDEX, i);
|
||||
return inportb(V_CRT_RW);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static void disable_video(void)
|
||||
{
|
||||
// Get the current value
|
||||
volatile unsigned char t = inportb(V_ATTR_IW);
|
||||
|
||||
// Reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
|
||||
// Clear the PAS bit
|
||||
t &= 0xDF;
|
||||
|
||||
// Set the port
|
||||
outportb(V_ATTR_IW, t);
|
||||
|
||||
// Reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static void enable_video(void)
|
||||
{
|
||||
// Get the current value
|
||||
volatile unsigned char t = inportb(V_ATTR_IW);
|
||||
|
||||
// Reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
|
||||
// Set the PAS bit
|
||||
t |= 0x20;
|
||||
|
||||
// set the port
|
||||
outportb(V_ATTR_IW, t);
|
||||
|
||||
// Reset the flip/flop
|
||||
inportb(V_ISTAT1_R);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static void unlock_crt_registers(void)
|
||||
{
|
||||
volatile unsigned char aux = get_crt(0x11);
|
||||
aux &= 0x7f;
|
||||
put_crt(0x11, aux);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static void load_regs(VgaModeInfo *regs)
|
||||
{
|
||||
int j;
|
||||
|
||||
disable_video();
|
||||
disable();
|
||||
|
||||
// Set misc register
|
||||
put_misc(regs->misc);
|
||||
|
||||
// Sequencer sync reset on
|
||||
put_sequence(0x00, 0x01);
|
||||
|
||||
// Sequencer registers
|
||||
for(j = 0; j <= 0x04; j++)
|
||||
{
|
||||
put_sequence(j, regs->sequencer[j]);
|
||||
}
|
||||
|
||||
// Sequencer reset off
|
||||
put_sequence(0x00, 0x03);
|
||||
|
||||
unlock_crt_registers();
|
||||
// crt registers
|
||||
for(j = 0; j <= 0x18; j++)
|
||||
{
|
||||
put_crt(j, regs->crt[j]);
|
||||
}
|
||||
|
||||
// Graphic registers
|
||||
for(j = 0; j <= 0x08; j++)
|
||||
{
|
||||
put_graph(j, regs->graphic[j]);
|
||||
}
|
||||
|
||||
// Attrib registers
|
||||
for(j = 0; j <= 0x14; j++)
|
||||
{
|
||||
put_attr(j, regs->attrib[j]);
|
||||
}
|
||||
|
||||
enable();
|
||||
enable_video();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool VgaSetMode(int mode)
|
||||
{
|
||||
VgaModeInfo* info = 0;
|
||||
|
||||
if(mode == VGA_320_200_60HZ)
|
||||
{
|
||||
info = &Vga320x200x60Hz;
|
||||
}
|
||||
else if(mode == VGA_320_200_70HZ)
|
||||
{
|
||||
info = &Vga320x200x70Hz;
|
||||
}
|
||||
else if(mode == VGA_320_240_60HZ)
|
||||
{
|
||||
info = &Vga320x240x60Hz;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
load_regs(info);
|
||||
return info->chained;
|
||||
}
|
||||
|
|
@ -1,34 +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-2003 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: vga.hxx,v 1.1 2003-02-17 05:17:42 bwmott Exp $
|
||||
//============================================================================
|
||||
|
||||
#ifndef VGA_HXX
|
||||
#define VGA_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
#define VGA_320_200_60HZ 1
|
||||
#define VGA_320_200_70HZ 2
|
||||
#define VGA_320_240_60HZ 3
|
||||
|
||||
/**
|
||||
Change the graphics mode to the specified mode.
|
||||
*/
|
||||
extern bool VgaSetMode(int mode);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:23 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;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 2004-05-24 17:18:23 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 2004-05-24 17:18:23 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
|
|
@ -0,0 +1,188 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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.1 2004-05-24 17:18:23 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;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//============================================================================
|
||||
//
|
||||
// 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 2004-05-24 17:18:23 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 2004-05-24 17:18:23 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
|
Loading…
Reference in New Issue