And so it begins. This is only symbolic ATM, but I've now killed

software rendering support.  I've been wanting to do this for years,
and finally the time has come.  So for now, you need OpenGL for Stella
to build and run.

Expect major breakage over the next few months, as I port to SDL2.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2829 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2013-09-27 19:47:15 +00:00
parent cda1e301e2
commit a911a5b368
11 changed files with 39 additions and 1243 deletions

View File

@ -1,860 +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-2013 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <sstream>
#include <SDL.h>
#include "bspf.hxx"
#include "Console.hxx"
#include "Font.hxx"
#include "OSystem.hxx"
#include "RectList.hxx"
#include "Settings.hxx"
#include "TIA.hxx"
#include "FrameBufferSoft.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSoft::FrameBufferSoft(OSystem* osystem)
: FrameBuffer(osystem),
myZoomLevel(2),
myRenderType(kSoftZoom_16),
myTiaDirty(false),
myInUIMode(false),
myRectList(NULL)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferSoft::~FrameBufferSoft()
{
delete myRectList;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSoft::initSubsystem(VideoMode& mode)
{
// Set up the rectangle list to be used in the dirty update
delete myRectList;
myRectList = new RectList();
if(!myRectList)
{
myOSystem->logMessage("ERROR: Unable to get memory for SDL rects", 0);
return false;
}
// Create the screen
return setVidMode(mode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FrameBufferSoft::about() const
{
ostringstream buf;
buf << "Video rendering: Software mode" << endl << setfill('0')
<< " Color: " << (int)myFormat->BitsPerPixel << " bit" << endl
<< " Rmask = " << hex << setw(8) << (int)myFormat->Rmask
<< ", Rshift = "<< dec << setw(2) << (int)myFormat->Rshift
<< ", Rloss = " << dec << setw(2) << (int)myFormat->Rloss << endl
<< " Gmask = " << hex << setw(8) << (int)myFormat->Gmask
<< ", Gshift = "<< dec << setw(2) << (int)myFormat->Gshift
<< ", Gloss = " << dec << setw(2) << (int)myFormat->Gloss << endl
<< " Bmask = " << hex << setw(8) << (int)myFormat->Bmask
<< ", Bshift = "<< dec << setw(2) << (int)myFormat->Bshift
<< ", Bloss = " << dec << setw(2) << (int)myFormat->Bloss << endl;
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferSoft::setVidMode(VideoMode& mode)
{
// Make sure to clear the screen
if(myScreen)
{
SDL_FillRect(myScreen, NULL, 0);
SDL_UpdateRect(myScreen, 0, 0, 0, 0);
}
myScreen = SDL_SetVideoMode(mode.screen_w, mode.screen_h, 0, mySDLFlags);
if(myScreen == NULL)
{
ostringstream buf;
buf << "ERROR: Unable to open SDL window: " << SDL_GetError() << endl;
myOSystem->logMessage(buf.str(), 0);
return false;
}
myFormat = myScreen->format;
myBytesPerPixel = myFormat->BytesPerPixel;
// Make sure the flags represent the current screen state
mySDLFlags = myScreen->flags;
// Make sure drawTIA() knows which renderer to use
switch(myBytesPerPixel)
{
case 2: // 16-bit
myPitch = myScreen->pitch >> 1;
myRenderType = myUsePhosphor ? kPhosphor_16 : kSoftZoom_16;
break;
case 3: // 24-bit
myPitch = myScreen->pitch;
myRenderType = myUsePhosphor ? kPhosphor_24 : kSoftZoom_24;
break;
case 4: // 32-bit
myPitch = myScreen->pitch >> 2;
myRenderType = myUsePhosphor ? kPhosphor_32 : kSoftZoom_32;
break;
}
myBaseOffset = mode.image_y * myPitch + mode.image_x;
// If software mode can open the given screen, it will always be in the
// requested format, or not at all; we only update mode when the screen
// is successfully created
mode.screen_w = myScreen->w;
mode.screen_h = myScreen->h;
myZoomLevel = mode.gfxmode.zoom;
// Erase old rects, since they've probably been scaled for
// a different sized screen
myRectList->start();
// Any previously allocated surfaces have probably changed as well,
// so we should refresh them
resetSurfaces();
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::invalidate()
{
if(myScreen)
SDL_FillRect(myScreen, NULL, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::drawTIA(bool fullRedraw)
{
const TIA& tia = myOSystem->console().tia();
uInt8* currentFrame = tia.currentFrameBuffer();
uInt8* previousFrame = tia.previousFrameBuffer();
uInt32 width = tia.width();
uInt32 height = tia.height();
switch(myRenderType)
{
case kSoftZoom_16:
{
SDL_LockSurface(myScreen);
uInt16* buffer = (uInt16*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
if(v != w || fullRedraw)
{
while(xstride--)
{
buffer[pos++] = (uInt16) myDefPalette[v];
buffer[pos++] = (uInt16) myDefPalette[v];
}
myTiaDirty = true;
}
else
pos += xstride + xstride;
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
break; // kSoftZoom_16
}
case kSoftZoom_24:
{
SDL_LockSurface(myScreen);
uInt8* buffer = (uInt8*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
if(v != w || fullRedraw)
{
uInt8 a = myDefPalette24[v][0],
b = myDefPalette24[v][1],
c = myDefPalette24[v][2];
while(xstride--)
{
buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c;
buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c;
}
myTiaDirty = true;
}
else // try to eliminate multiply whereever possible
pos += xstride + xstride + xstride + xstride + xstride + xstride;
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
break; // kSoftZoom_24
}
case kSoftZoom_32:
{
SDL_LockSurface(myScreen);
uInt32* buffer = (uInt32*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
if(v != w || fullRedraw)
{
while(xstride--)
{
buffer[pos++] = (uInt32) myDefPalette[v];
buffer[pos++] = (uInt32) myDefPalette[v];
}
myTiaDirty = true;
}
else
pos += xstride + xstride;
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
break; // kSoftZoom_32
}
case kPhosphor_16:
{
SDL_LockSurface(myScreen);
uInt16* buffer = (uInt16*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
while(xstride--)
{
buffer[pos++] = (uInt16) myAvgPalette[v][w];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
}
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
myTiaDirty = true;
break; // kPhosphor_16
}
case kPhosphor_24:
{
SDL_LockSurface(myScreen);
uInt8* buffer = (uInt8*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
uInt8 a, b, c;
uInt32 pixel = myAvgPalette[v][w];
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
{
a = (pixel & myFormat->Bmask) >> myFormat->Bshift;
b = (pixel & myFormat->Gmask) >> myFormat->Gshift;
c = (pixel & myFormat->Rmask) >> myFormat->Rshift;
}
else
{
a = (pixel & myFormat->Rmask) >> myFormat->Rshift;
b = (pixel & myFormat->Gmask) >> myFormat->Gshift;
c = (pixel & myFormat->Bmask) >> myFormat->Bshift;
}
while(xstride--)
{
buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c;
buffer[pos++] = a; buffer[pos++] = b; buffer[pos++] = c;
}
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
myTiaDirty = true;
break; // kPhosphor_24
}
case kPhosphor_32:
{
SDL_LockSurface(myScreen);
uInt32* buffer = (uInt32*)myScreen->pixels + myBaseOffset;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y)
{
uInt32 ystride = myZoomLevel;
while(ystride--)
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x)
{
const uInt32 bufofs = bufofsY + x;
uInt32 xstride = myZoomLevel;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
while(xstride--)
{
buffer[pos++] = (uInt32) myAvgPalette[v][w];
buffer[pos++] = (uInt32) myAvgPalette[v][w];
}
}
screenofsY += myPitch;
}
bufofsY += width;
}
SDL_UnlockSurface(myScreen);
myTiaDirty = true;
break; // kPhosphor_32
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::postFrameUpdate()
{
if(myTiaDirty && !myInUIMode)
{
SDL_UpdateRect(myScreen, 0, 0, 0, 0);
myTiaDirty = false;
}
else if(myRectList->numRects() > 0)
{
//myRectList->print(myScreen->w, myScreen->h);
SDL_UpdateRects(myScreen, myRectList->numRects(), myRectList->rects());
}
myRectList->start();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::enablePhosphor(bool enable, int blend)
{
myUsePhosphor = enable;
myPhosphorBlend = blend;
// Make sure drawMediaSource() knows which renderer to use
switch(myBytesPerPixel)
{
case 2: // 16-bit
myRenderType = myUsePhosphor ? kPhosphor_16 : kSoftZoom_16;
break;
case 3: // 24-bit
myRenderType = myUsePhosphor ? kPhosphor_24 : kSoftZoom_24;
break;
case 4: // 32-bit
myRenderType = myUsePhosphor ? kPhosphor_32 : kSoftZoom_32;
break;
}
myRedrawEntireFrame = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurface* FrameBufferSoft::createSurface(int w, int h, bool isBase) const
{
// For some unknown reason, OSX in software fullscreen mode doesn't like
// to use the underlying surface directly
// I suspect it's an SDL compatibility thing, since I get errors
// referencing Quartz vs. QuickDraw, and then a program crash
// For now, we'll just always use entire surfaces for OSX
// I don't think this will have much effect, since OpenGL mode is the
// preferred method in OSX (basically, all OSX installations have OpenGL
// support)
#ifdef MAC_OSX
isBase = false;
#endif
SDL_Surface* surface = isBase ? myScreen :
SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, myFormat->BitsPerPixel,
myFormat->Rmask, myFormat->Gmask, myFormat->Bmask,
myFormat->Amask);
return new FBSurfaceSoft(*this, surface, w, h, isBase);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferSoft::scanline(uInt32 row, uInt8* data) const
{
// Make sure no pixels are being modified
SDL_LockSurface(myScreen);
uInt32 pixel = 0;
uInt8 *p, r, g, b;
// Row will be offset by the amount the actual image is shifted down
const GUI::Rect& image = imageRect();
row += image.y();
for(Int32 x = 0; x < myScreen->w; ++x)
{
p = (Uint8*) ((uInt8*)myScreen->pixels + // Start at top of RAM
(row * myScreen->pitch) + // Go down 'row' lines
((x + image.x()) * myBytesPerPixel)); // Go in 'x' pixels
switch(myBytesPerPixel)
{
case 1:
pixel = *p;
break;
case 2:
pixel = *(Uint16*) p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
pixel = p[0] << 16 | p[1] << 8 | p[2];
else
pixel = p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
pixel = *(Uint32*) p;
break;
}
SDL_GetRGB(pixel, myScreen->format, &r, &g, &b);
data[x * 3 + 0] = r;
data[x * 3 + 1] = g;
data[x * 3 + 2] = b;
}
SDL_UnlockSurface(myScreen);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// FBSurfaceSoft implementation follows ...
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSoft::FBSurfaceSoft(const FrameBufferSoft& buffer, SDL_Surface* surface,
uInt32 w, uInt32 h, bool isBase)
: myFB(buffer),
mySurface(surface),
myWidth(w),
myHeight(h),
myIsBaseSurface(isBase),
mySurfaceIsDirty(false),
myPitch(0),
myXOrig(0),
myYOrig(0),
myXOffset(0),
myYOffset(0)
{
reload();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSoft::~FBSurfaceSoft()
{
if(!myIsBaseSurface)
SDL_FreeSurface(mySurface);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color)
{
// Horizontal line
SDL_Rect tmp;
tmp.x = x + myXOffset;
tmp.y = y + myYOffset;
tmp.w = x2 - x + 1;
tmp.h = 1;
SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color)
{
// Vertical line
SDL_Rect tmp;
tmp.x = x + myXOffset;
tmp.y = y + myYOffset;
tmp.w = 1;
tmp.h = y2 - y + 1;
SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color)
{
// Fill the rectangle
SDL_Rect tmp;
tmp.x = x + myXOffset;
tmp.y = y + myYOffset;
tmp.w = w;
tmp.h = h;
SDL_FillRect(mySurface, &tmp, myFB.myDefPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::drawChar(const GUI::Font& font, uInt8 chr,
uInt32 tx, uInt32 ty, uInt32 color)
{
const FontDesc& desc = font.desc();
// If this character is not included in the font, use the default char.
if(chr < desc.firstchar || chr >= desc.firstchar + desc.size)
{
if (chr == ' ') return;
chr = desc.defaultchar;
}
chr -= desc.firstchar;
// Get the bounding box of the character
int bbw, bbh, bbx, bby;
if(!desc.bbx)
{
bbw = desc.fbbw;
bbh = desc.fbbh;
bbx = desc.fbbx;
bby = desc.fbby;
}
else
{
bbw = desc.bbx[chr].w;
bbh = desc.bbx[chr].h;
bbx = desc.bbx[chr].x;
bby = desc.bbx[chr].y;
}
const uInt16* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh));
switch(myFB.myBytesPerPixel)
{
case 2:
{
// Get buffer position where upper-left pixel of the character will be drawn
uInt16* buffer = (uInt16*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh);
for(int y = 0; y < bbh; y++)
{
const uInt16 ptr = *tmp++;
uInt16 mask = 0x8000;
for(int x = 0; x < bbw; x++, mask >>= 1)
if(ptr & mask)
buffer[x] = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
break;
}
case 3:
{
// Get buffer position where upper-left pixel of the character will be drawn
uInt8* buffer = (uInt8*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh);
uInt8 a = myFB.myDefPalette24[color][0],
b = myFB.myDefPalette24[color][1],
c = myFB.myDefPalette24[color][2];
for(int y = 0; y < bbh; y++, buffer += myPitch)
{
const uInt16 ptr = *tmp++;
uInt16 mask = 0x8000;
uInt8* buf_ptr = buffer;
for(int x = 0; x < bbw; x++, mask >>= 1)
{
if(ptr & mask)
{
*buf_ptr++ = a; *buf_ptr++ = b; *buf_ptr++ = c;
}
else
buf_ptr += 3;
}
}
break;
}
case 4:
{
// Get buffer position where upper-left pixel of the character will be drawn
uInt32* buffer = (uInt32*)getBasePtr(tx + bbx, ty + desc.ascent - bby - bbh);
for(int y = 0; y < bbh; y++, buffer += myPitch)
{
const uInt16 ptr = *tmp++;
uInt16 mask = 0x8000;
for(int x = 0; x < bbw; x++, mask >>= 1)
if(ptr & mask)
buffer[x] = (uInt32) myFB.myDefPalette[color];
}
break;
}
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty,
uInt32 color, uInt32 h)
{
SDL_Rect rect;
rect.y = ty + myYOffset;
rect.w = rect.h = 1;
for(uInt32 y = 0; y < h; y++)
{
rect.x = tx + myXOffset;
uInt32 mask = 0xF0000000;
for(uInt32 x = 0; x < 8; x++, mask >>= 4)
{
if(bitmap[y] & mask)
SDL_FillRect(mySurface, &rect, myFB.myDefPalette[color]);
rect.x++;
}
rect.y++;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::drawPixels(uInt32* data, uInt32 tx, uInt32 ty,
uInt32 numpixels)
{
SDL_Rect rect;
rect.x = tx + myXOffset;
rect.y = ty + myYOffset;
rect.w = rect.h = 1;
for(uInt32 x = 0; x < numpixels; ++x)
{
SDL_FillRect(mySurface, &rect, data[x]);
rect.x++;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty)
{
const FBSurfaceSoft* s = (const FBSurfaceSoft*) surface;
SDL_Rect dstrect;
dstrect.x = tx + myXOffset;
dstrect.y = ty + myYOffset;
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = s->myWidth;
srcrect.h = s->myHeight;
SDL_BlitSurface(s->mySurface, &srcrect, mySurface, &dstrect);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
{
//cerr << " -> addDirtyRect: x = " << x << ", y = " << y << ", w = " << w << ", h = " << h << endl;
// Base surfaces use dirty-rectangle updates, since they can be quite
// large, and updating the entire surface each frame would be too slow
// Non-base surfaces are usually smaller, and can be updated entirely
if(myIsBaseSurface)
{
// Add a dirty rect to the UI rectangle list
SDL_Rect temp;
temp.x = x + myXOrig; temp.y = y + myYOrig; temp.w = w; temp.h = h;
myFB.myRectList->add(&temp);
}
else
{
SDL_Rect temp;
temp.x = myXOrig; temp.y = myYOrig; temp.w = myWidth; temp.h = myHeight;
myFB.myRectList->add(&temp);
// Indicate that at least one dirty rect has been added
// This is an optimization for the update() method
mySurfaceIsDirty = true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::getPos(uInt32& x, uInt32& y) const
{
// Return the origin of the 'usable' area of a surface
if(myIsBaseSurface)
{
x = myXOffset;
y = myYOffset;
}
else
{
x = myXOrig;
y = myYOrig;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::setPos(uInt32 x, uInt32 y)
{
myXOrig = x;
myYOrig = y;
if(myIsBaseSurface)
{
myXOffset = myFB.imageRect().x();
myYOffset = myFB.imageRect().y();
}
else
{
myXOffset = myYOffset = 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::setWidth(uInt32 w)
{
myWidth = BSPF_min(w, (uInt32)mySurface->w);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::setHeight(uInt32 h)
{
myHeight = BSPF_min(h, (uInt32)mySurface->h);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::translateCoords(Int32& x, Int32& y) const
{
x -= myXOrig;
y -= myYOrig;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::update()
{
// Since this method is called each frame, we only blit the surfaces when
// absolutely necessary
if(mySurfaceIsDirty /* && !myIsBaseSurface */)
{
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = myWidth;
srcrect.h = myHeight;
SDL_Rect dstrect;
dstrect.x = myXOrig;
dstrect.y = myYOrig;
dstrect.w = myWidth;
dstrect.h = myHeight;
SDL_BlitSurface(mySurface, &srcrect, myFB.myScreen, &dstrect);
mySurfaceIsDirty = false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSoft::reload()
{
switch(mySurface->format->BytesPerPixel)
{
case 2: // 16-bit
myPitch = mySurface->pitch >> 1;
break;
case 3: // 24-bit
myPitch = mySurface->pitch;
break;
case 4: // 32-bit
myPitch = mySurface->pitch >> 2;
break;
}
}

View File

@ -1,230 +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-2013 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef FRAMEBUFFER_SOFT_HXX
#define FRAMEBUFFER_SOFT_HXX
#include <SDL.h>
class OSystem;
class RectList;
#include "bspf.hxx"
#include "FrameBuffer.hxx"
/**
This class implements an SDL software framebuffer.
@author Stephen Anthony
@version $Id$
*/
class FrameBufferSoft : public FrameBuffer
{
friend class FBSurfaceSoft;
public:
/**
Creates a new software framebuffer
*/
FrameBufferSoft(OSystem* osystem);
/**
Destructor
*/
virtual ~FrameBufferSoft();
//////////////////////////////////////////////////////////////////////
// The following are derived from public methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
Enable/disable phosphor effect.
*/
void enablePhosphor(bool enable, int blend);
/**
This method is called to retrieve the R/G/B data from the given pixel.
@param pixel The pixel containing R/G/B data
@param r The red component of the color
@param g The green component of the color
@param b The blue component of the color
*/
void getRGB(Uint32 pixel, Uint8* r, Uint8* g, Uint8* b) const
{ SDL_GetRGB(pixel, myScreen->format, r, g, b); }
/**
This method 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.
*/
Uint32 mapRGB(Uint8 r, Uint8 g, Uint8 b) const
{ return SDL_MapRGB(myScreen->format, r, g, b); }
/**
This method is called to query the type of the FrameBuffer.
*/
BufferType type() const { return kSoftBuffer; }
/**
This method is called to get the specified scanline data.
@param row The row we are looking for
@param data The actual pixel data (in bytes)
*/
void scanline(uInt32 row, uInt8* data) const;
protected:
//////////////////////////////////////////////////////////////////////
// The following are derived from protected methods in FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
This method is called to initialize the video subsystem
with the given video mode. Normally, it will also call setVidMode().
@param mode The video mode to use
@return False on any errors, else true
*/
bool initSubsystem(VideoMode& mode);
/**
This method is called to change to the given video mode. If the mode
is successfully changed, 'mode' holds the actual dimensions used.
@param mode The video mode to use
@return False on any errors (in which case 'mode' is invalid), else true
*/
bool setVidMode(VideoMode& mode);
/**
This method is called to invalidate the contents of the entire
framebuffer (ie, mark the current content as invalid, and erase it on
the next drawing pass).
*/
void invalidate();
/**
This method is called to create a surface compatible with the one
currently in use, but having the given dimensions.
@param w The requested width of the new surface.
@param h The requested height of the new surface.
@param useBase Use the base surface instead of creating a new one
*/
FBSurface* createSurface(int w, int h, bool useBase = false) const;
/**
This method should be called anytime the TIA needs to be redrawn
to the screen (full indicating that a full redraw is required).
*/
void drawTIA(bool full);
/**
This method is called after any drawing is done (per-frame).
*/
void postFrameUpdate();
/**
This method is called to provide information about the FrameBuffer.
*/
string about() const;
private:
int myZoomLevel;
int myBytesPerPixel;
int myBaseOffset;
int myPitch;
SDL_PixelFormat* myFormat;
enum RenderType {
kSoftZoom_16,
kSoftZoom_24,
kSoftZoom_32,
kPhosphor_16,
kPhosphor_24,
kPhosphor_32
};
RenderType myRenderType;
// Indicates if the TIA image has been modified
bool myTiaDirty;
// Indicates if we're in a purely UI mode
bool myInUIMode;
// Used in the dirty update of rectangles in non-TIA modes
RectList* myRectList;
};
/**
A surface suitable for software rendering mode.
@author Stephen Anthony
@version $Id$
*/
class FBSurfaceSoft : public FBSurface
{
public:
FBSurfaceSoft(const FrameBufferSoft& buffer, SDL_Surface* surface,
uInt32 w, uInt32 h, bool isBase);
virtual ~FBSurfaceSoft();
void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color);
void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color);
void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color);
void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y, uInt32 color);
void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8);
void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels);
void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y);
void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
void getPos(uInt32& x, uInt32& y) const;
void setPos(uInt32 x, uInt32 y);
uInt32 getWidth() const { return myWidth; }
uInt32 getHeight() const { return myHeight; }
void setWidth(uInt32 w);
void setHeight(uInt32 h);
void translateCoords(Int32& x, Int32& y) const;
void update();
void free() { } // Not required for software mode
void reload();
private:
void* getBasePtr(uInt32 x, uInt32 y) {
return static_cast<void *>(static_cast<uInt8*>(mySurface->pixels) +
(myYOffset + y) * mySurface->pitch + (myXOffset + x) *
mySurface->format->BytesPerPixel);
}
private:
const FrameBufferSoft& myFB;
SDL_Surface* mySurface;
uInt32 myWidth, myHeight;
bool myIsBaseSurface;
bool mySurfaceIsDirty;
int myPitch;
uInt32 myXOrig, myYOrig;
uInt32 myXOffset, myYOffset;
};
#endif

View File

@ -1,96 +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-2013 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include <SDL.h>
#include "bspf.hxx"
#include "RectList.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RectList::print(int boundWidth, int boundHeight)
{
cerr << "RectList: rects = " << numRects() << endl;
for(Uint32 i = 0; i < currentRect; ++i)
{
cerr << "Rect " << i << endl
<< " x = " << rectArray[i].x << endl
<< " y = " << rectArray[i].y << endl
<< " w = " << rectArray[i].w << endl
<< " h = " << rectArray[i].h << endl;
if((rectArray[i].x + rectArray[i].w) > boundWidth ||
(rectArray[i].y + rectArray[i].h) > boundHeight)
cerr << " TOO LARGE" << endl;
cerr << endl;
}
}

View File

@ -1,44 +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-2013 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef RECTLIST_HXX
#define RECTLIST_HXX
#include <SDL.h>
class RectList
{
public:
RectList(Uint32 size = 256);
~RectList();
void add(SDL_Rect* rect);
SDL_Rect* rects();
Uint32 numRects();
void start();
void print(int boundWidth, int boundHeight);
private:
Uint32 currentSize, currentRect;
SDL_Rect* rectArray;
};
#endif

View File

@ -22,7 +22,7 @@
#include <cstdlib>
#define STELLA_VERSION "3.9.3_svn"
#define STELLA_VERSION "3.9.100_svn"
#define STELLA_BUILD atoi("$Rev$" + 6)
#endif

View File

@ -4,14 +4,12 @@ MODULE_OBJS := \
src/common/mainSDL.o \
src/common/Base.o \
src/common/SoundSDL.o \
src/common/FrameBufferSoft.o \
src/common/FrameBufferGL.o \
src/common/FBSurfaceGL.o \
src/common/FBSurfaceTIA.o \
src/common/FSNodeZIP.o \
src/common/PNGLibrary.o \
src/common/MouseControl.o \
src/common/RectList.o \
src/common/ZipHandler.o
MODULE_DIRS += \

View File

@ -128,8 +128,12 @@ void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, in
void TiaOutputWidget::drawWidget(bool hilite)
{
//cerr << "TiaOutputWidget::drawWidget\n";
FBSurface& s = dialog().surface();
renderToSurface(dialog().surface());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TiaOutputWidget::renderToSurface(FBSurface& s)
{
const uInt32 width = instance().console().tia().width(),
height = instance().console().tia().height();

View File

@ -22,6 +22,7 @@
class GuiObject;
class ContextMenu;
class FBSurface;
class TiaZoomWidget;
#include "Widget.hxx"
@ -38,6 +39,8 @@ class TiaOutputWidget : public Widget, public CommandSender
void loadConfig();
void setZoomWidget(TiaZoomWidget* w) { myZoom = w; }
void saveSnapshot();
// Eventually, these methods will enable access to the onscreen TIA image
// For example, clicking an area may cause an action
// (fill to this scanline, etc).
@ -55,6 +58,9 @@ class TiaOutputWidget : public Widget, public CommandSender
void drawWidget(bool hilite);
bool wantsFocus() { return false; }
private:
void renderToSurface(FBSurface& s);
private:
ContextMenu* myMenu;
TiaZoomWidget* myZoom;
@ -64,6 +70,9 @@ class TiaOutputWidget : public Widget, public CommandSender
// Create this buffer once, instead of allocating it each time the
// TIA image is redrawn
uInt32 myLineBuffer[320];
// Surface to use when taking snapshots
FBSurface* mySnapSurface;
};
#endif

View File

@ -24,7 +24,6 @@
#include "Settings.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferSoft.hxx"
#ifdef DISPLAY_OPENGL
#include "FrameBufferGL.hxx"
#endif
@ -63,11 +62,6 @@ class MediaFactory
}
#endif
// If OpenGL failed, or if it wasn't requested, create the appropriate
// software framebuffer
if(!fb)
fb = new FrameBufferSoft(osystem);
// This should never happen
assert(fb != NULL);

View File

@ -24,10 +24,13 @@
#include "bspf.hxx"
#include "DebuggerDialog.hxx"
#include "OSystem.hxx"
#include "Version.hxx"
#ifdef DEBUGGER_SUPPORT
#include "DebuggerDialog.hxx"
#endif
#include "Settings.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -120,8 +123,11 @@ Settings::Settings(OSystem* osystem)
setInternal("lastrom", "");
// UI-related options
#ifdef DEBUGGER_SUPPORT
setInternal("dbg.res",
GUI::Size(DebuggerDialog::kMediumFontMinW, DebuggerDialog::kMediumFontMinH));
GUI::Size(DebuggerDialog::kMediumFontMinW,
DebuggerDialog::kMediumFontMinH));
#endif
setInternal("uipalette", "0");
setInternal("listdelay", "300");
setInternal("mwheel", "4");
@ -139,6 +145,7 @@ Settings::Settings(OSystem* osystem)
setExternal("romloadcount", "0");
setExternal("maxres", "");
#ifdef DEBUGGER_SUPPORT
// Debugger/disassembly options
setInternal("dbg.fontstyle", "0");
setInternal("dbg.uhex", "true");
@ -146,9 +153,12 @@ Settings::Settings(OSystem* osystem)
setInternal("dis.gfxformat", "2");
setInternal("dis.showaddr", "true");
setInternal("dis.relocate", "false");
#endif
#ifdef DTHUMB_SUPPORT
// Thumb ARM emulation options
setInternal("thumb.trapfatal", "true");
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -22,7 +22,6 @@
#include "bspf.hxx"
#include "Dialog.hxx"
#include "DebuggerDialog.hxx"
#include "OSystem.hxx"
#include "ListWidget.hxx"
#include "PopUpWidget.hxx"
@ -31,6 +30,9 @@
#include "StringList.hxx"
#include "TabWidget.hxx"
#include "Widget.hxx"
#ifdef DEBUGGER_SUPPORT
#include "DebuggerDialog.hxx"
#endif
#include "UIDialog.hxx"
@ -160,6 +162,7 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent,
// 2) Debugger options
wid.clear();
tabID = myTab->addTab(" Debugger ");
#ifdef DEBUGGER_SUPPORT
lwidth = font.getStringWidth("Debugger Height: ");
xpos = ypos = vBorder;
@ -239,6 +242,10 @@ UIDialog::UIDialog(OSystem* osystem, DialogContainer* parent,
// Add items for tab 1
addToFocusList(wid, myTab, tabID);
#else
new StaticTextWidget(myTab, font, 0, 20, _w-20, fontHeight,
"Debugger support not included", kTextAlignCenter);
#endif
//////////////////////////////////////////////////////////
// 3) Misc. options
@ -438,6 +445,7 @@ void UIDialog::setDefaults()
case 1: // Debugger options
{
#ifdef DEBUGGER_SUPPORT
int w = BSPF_min(instance().desktopWidth(), (uInt32)DebuggerDialog::kMediumFontMinW);
int h = BSPF_min(instance().desktopHeight(), (uInt32)DebuggerDialog::kMediumFontMinH);
myDebuggerWidthSlider->setValue(w);
@ -445,6 +453,7 @@ void UIDialog::setDefaults()
myDebuggerHeightSlider->setValue(h);
myDebuggerHeightLabel->setValue(h);
myDebuggerFontStyle->setSelected("0");
#endif
break;
}
@ -474,6 +483,7 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
myLauncherHeightLabel->setValue(myLauncherHeightSlider->getValue());
break;
#ifdef DEBUGGER_SUPPORT
case kDWidthChanged:
myDebuggerWidthLabel->setValue(myDebuggerWidthSlider->getValue());
break;
@ -502,6 +512,7 @@ void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
myDebuggerHeightSlider->setValue(DebuggerDialog::kLargeFontMinH);
myDebuggerHeightLabel->setValue(DebuggerDialog::kLargeFontMinH);
break;
#endif
case kOKCmd:
saveConfig();