And now that the FrameBuffer class is partially working, time to break

things again :)  Work continues on refactoring the FBSurface code, and
moving thing out of the xxxSDL classes that don't really have anything
to do with SDL.  This will also make it easier to port Stella to other
graphical toolkits.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2878 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2014-04-30 16:53:21 +00:00
parent 61689a9563
commit e7719c334e
5 changed files with 414 additions and 364 deletions

147
src/emucore/FBSurface.cxx Normal file
View File

@ -0,0 +1,147 @@
//============================================================================
//
// 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-2014 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 "FBSurface.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB)
{
hLine(x + 1, y, x + w - 2, colorA);
hLine(x, y + 1, x + w - 1, colorA);
vLine(x, y + 1, y + h - 2, colorA);
vLine(x + 1, y, y + h - 1, colorA);
hLine(x + 1, y + h - 2, x + w - 1, colorB);
hLine(x + 1, y + h - 1, x + w - 2, colorB);
vLine(x + w - 1, y + 1, y + h - 2, colorB);
vLine(x + w - 2, y + 1, y + h - 1, colorB);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style)
{
switch(style)
{
case kSolidLine:
hLine(x, y, x + w - 1, color);
hLine(x, y + h - 1, x + w - 1, color);
vLine(x, y, y + h - 1, color);
vLine(x + w - 1, y, y + h - 1, color);
break;
case kDashLine:
unsigned int i, skip, lwidth = 1;
for(i = x, skip = 1; i < x+w-1; i=i+lwidth+1, ++skip)
{
if(skip % 2)
{
hLine(i, y, i + lwidth, color);
hLine(i, y + h - 1, i + lwidth, color);
}
}
for(i = y, skip = 1; i < y+h-1; i=i+lwidth+1, ++skip)
{
if(skip % 2)
{
vLine(x, i, i + lwidth, color);
vLine(x + w - 1, i, i + lwidth, color);
}
}
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::drawString(const GUI::Font& font, const string& s,
int x, int y, int w,
uInt32 color, TextAlignment align,
int deltax, bool useEllipsis)
{
const int leftX = x, rightX = x + w;
unsigned int i;
int width = font.getStringWidth(s);
string str;
if(useEllipsis && width > w)
{
// String is too wide. So we shorten it "intelligently", by replacing
// parts of it by an ellipsis ("..."). There are three possibilities
// for this: replace the start, the end, or the middle of the string.
// What is best really depends on the context; but unless we want to
// make this configurable, replacing the middle probably is a good
// compromise.
const int ellipsisWidth = font.getStringWidth("...");
// SLOW algorithm to remove enough of the middle. But it is good enough for now.
const int halfWidth = (w - ellipsisWidth) / 2;
int w2 = 0;
for(i = 0; i < s.size(); ++i)
{
int charWidth = font.getCharWidth(s[i]);
if(w2 + charWidth > halfWidth)
break;
w2 += charWidth;
str += s[i];
}
// At this point we know that the first 'i' chars are together 'w2'
// pixels wide. We took the first i-1, and add "..." to them.
str += "...";
// The original string is width wide. Of those we already skipped past
// w2 pixels, which means (width - w2) remain.
// The new str is (w2+ellipsisWidth) wide, so we can accomodate about
// (w - (w2+ellipsisWidth)) more pixels.
// Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) =
// (width + ellipsisWidth - w)
int skip = width + ellipsisWidth - w;
for(; i < s.size() && skip > 0; ++i)
skip -= font.getCharWidth(s[i]);
// Append the remaining chars, if any
for(; i < s.size(); ++i)
str += s[i];
width = font.getStringWidth(str);
}
else
str = s;
if(align == kTextAlignCenter)
x = x + (w - width - 1)/2;
else if(align == kTextAlignRight)
x = x + w - width;
x += deltax;
for(i = 0; i < str.size(); ++i)
{
w = font.getCharWidth(str[i]);
if(x+w > rightX)
break;
if(x >= leftX)
drawChar(font, str[i], x, y, color);
x += w;
}
}

262
src/emucore/FBSurface.hxx Normal file
View File

@ -0,0 +1,262 @@
//============================================================================
//
// 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-2014 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 FBSURFACE_HXX
#define FBSURFACE_HXX
#include "bspf.hxx"
#include "Font.hxx"
/**
This class is basically a thin wrapper around the video toolkit 'surface'
structure. We do it this way so the actual video toolkit won't be dragged
into the depths of the codebase. All drawing is done into FBSurfaces,
which are then drawn into the FrameBuffer. Each FrameBuffer-derived class
is responsible for extending an FBSurface object suitable to the
FrameBuffer type.
@author Stephen Anthony
*/
// Text alignment modes for drawString()
enum TextAlignment {
kTextAlignLeft,
kTextAlignCenter,
kTextAlignRight
};
// Line types for drawing rectangular frames
enum FrameStyle {
kSolidLine,
kDashLine
};
class FBSurface
{
public:
/**
Creates a new FBSurface object
*/
FBSurface() { }
/**
Destructor
*/
virtual ~FBSurface() { }
/**
This method should be called to draw a horizontal line.
@param x The first x coordinate
@param y The y coordinate
@param x2 The second x coordinate
@param color The color of the line
*/
virtual void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { }
/**
This method should be called to draw a vertical line.
@param x The x coordinate
@param y The first y coordinate
@param y2 The second y coordinate
@param color The color of the line
*/
virtual void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { }
/**
This method should be called to draw a filled rectangle.
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
@param color
*/
virtual void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color) { }
/**
This method should be called to draw the specified character.
@param font The font to use to draw the character
@param c The character to draw
@param x The x coordinate
@param y The y coordinate
@param color The color of the character
*/
virtual void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y,
uInt32 color) { }
/**
This method should be called to draw the bitmap image.
@param bitmap The data to draw
@param x The x coordinate
@param y The y coordinate
@param color The color of the character
@param h The height of the data image
*/
virtual void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color,
uInt32 h = 8) { }
/**
This method should be called to convert and copy a given row of pixel
data into a FrameBuffer surface. The pixels must already be in the
format used by the surface.
@param data The data in uInt8 R/G/B format
@param row The row of the surface the data should be placed in
@param rowbytes The number of bytes in row of 'data'
*/
virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels) { }
/**
This method should be called copy the contents of the given
surface into the FrameBuffer surface.
@param surface The data to draw
@param x The x coordinate
@param y The y coordinate
*/
virtual void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y) { }
/**
This method should be called to add a dirty rectangle
(ie, an area of the screen that has changed)
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
*/
virtual void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { }
/**
This method answers the current position of the surface.
*/
virtual void getPos(uInt32& x, uInt32& y) const { }
/**
This method should be called to set the position of the surface.
*/
virtual void setPos(uInt32 x, uInt32 y) { }
/**
This method answers the current dimensions of the surface.
*/
virtual uInt32 getWidth() const { return 0; }
virtual uInt32 getHeight() const { return 0; }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setWidth(uInt32 w) { }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setHeight(uInt32 h) { }
/**
This method should be called to translate the given coordinates
to the surface coordinates.
@param x X coordinate to translate
@param y Y coordinate to translate
*/
virtual void translateCoords(Int32& x, Int32& y) const { }
/**
This method should be called to draw the surface to the screen.
*/
virtual void update() { }
/**
This method should be called to reset the surface to empty
pixels / colour black.
*/
virtual void invalidate() { }
/**
This method should be called to free any resources being used by
the surface.
*/
virtual void free() { }
/**
This method should be called to reload the surface data/state.
It will normally be called after free().
*/
virtual void reload() { }
/**
This method 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
@param colorA Lighter color for outside line.
@param colorB Darker color for inside line.
*/
virtual void box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB);
/**
This method should be called to draw a framed rectangle.
I'm not exactly sure what it is, so I can't explain it :)
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
@param color The color of the surrounding frame
*/
virtual void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style = kSolidLine);
/**
This method should be called to draw the specified string.
@param font The font to draw the string with
@param str The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param h The height of the string area
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax
@param useEllipsis Whether to use '...' when the string is too long
*/
virtual void drawString(
const GUI::Font& font, const string& s, int x, int y, int w,
uInt32 color, TextAlignment align = kTextAlignLeft,
int deltax = 0, bool useEllipsis = true);
protected:
/**
This method answers the current position of the surface.
*/
// virtual void getBufferPtr(uInt32& x, uInt32& y) const = 0;
};
#endif

View File

@ -37,6 +37,7 @@
#include "Settings.hxx" #include "Settings.hxx"
#include "TIA.hxx" #include "TIA.hxx"
#include "FBSurface.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
@ -917,10 +918,11 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight)
); );
} }
#if 0 //FIXSDL
cerr << "Windowed modes:\n" << myWindowedModeList << endl cerr << "Windowed modes:\n" << myWindowedModeList << endl
<< "Fullscreen modes:\n" << myFullscreenModeList << endl << "Fullscreen modes:\n" << myFullscreenModeList << endl
<< endl; << endl;
#endif
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1108,137 +1110,6 @@ void FrameBuffer::VideoModeList::setZoom(uInt32 zoom)
myIdx = 0; myIdx = 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// FBSurface implementation
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB)
{
hLine(x + 1, y, x + w - 2, colorA);
hLine(x, y + 1, x + w - 1, colorA);
vLine(x, y + 1, y + h - 2, colorA);
vLine(x + 1, y, y + h - 1, colorA);
hLine(x + 1, y + h - 2, x + w - 1, colorB);
hLine(x + 1, y + h - 1, x + w - 2, colorB);
vLine(x + w - 1, y + 1, y + h - 2, colorB);
vLine(x + w - 2, y + 1, y + h - 1, colorB);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style)
{
switch(style)
{
case kSolidLine:
hLine(x, y, x + w - 1, color);
hLine(x, y + h - 1, x + w - 1, color);
vLine(x, y, y + h - 1, color);
vLine(x + w - 1, y, y + h - 1, color);
break;
case kDashLine:
unsigned int i, skip, lwidth = 1;
for(i = x, skip = 1; i < x+w-1; i=i+lwidth+1, ++skip)
{
if(skip % 2)
{
hLine(i, y, i + lwidth, color);
hLine(i, y + h - 1, i + lwidth, color);
}
}
for(i = y, skip = 1; i < y+h-1; i=i+lwidth+1, ++skip)
{
if(skip % 2)
{
vLine(x, i, i + lwidth, color);
vLine(x + w - 1, i, i + lwidth, color);
}
}
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurface::drawString(const GUI::Font& font, const string& s,
int x, int y, int w,
uInt32 color, TextAlignment align,
int deltax, bool useEllipsis)
{
const int leftX = x, rightX = x + w;
unsigned int i;
int width = font.getStringWidth(s);
string str;
if(useEllipsis && width > w)
{
// String is too wide. So we shorten it "intelligently", by replacing
// parts of it by an ellipsis ("..."). There are three possibilities
// for this: replace the start, the end, or the middle of the string.
// What is best really depends on the context; but unless we want to
// make this configurable, replacing the middle probably is a good
// compromise.
const int ellipsisWidth = font.getStringWidth("...");
// SLOW algorithm to remove enough of the middle. But it is good enough for now.
const int halfWidth = (w - ellipsisWidth) / 2;
int w2 = 0;
for(i = 0; i < s.size(); ++i)
{
int charWidth = font.getCharWidth(s[i]);
if(w2 + charWidth > halfWidth)
break;
w2 += charWidth;
str += s[i];
}
// At this point we know that the first 'i' chars are together 'w2'
// pixels wide. We took the first i-1, and add "..." to them.
str += "...";
// The original string is width wide. Of those we already skipped past
// w2 pixels, which means (width - w2) remain.
// The new str is (w2+ellipsisWidth) wide, so we can accomodate about
// (w - (w2+ellipsisWidth)) more pixels.
// Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) =
// (width + ellipsisWidth - w)
int skip = width + ellipsisWidth - w;
for(; i < s.size() && skip > 0; ++i)
skip -= font.getCharWidth(s[i]);
// Append the remaining chars, if any
for(; i < s.size(); ++i)
str += s[i];
width = font.getStringWidth(str);
}
else
str = s;
if(align == kTextAlignCenter)
x = x + (w - width - 1)/2;
else if(align == kTextAlignRight)
x = x + w - width;
x += deltax;
for(i = 0; i < str.size(); ++i)
{
w = font.getCharWidth(str[i]);
if(x+w > rightX)
break;
if(x >= leftX)
drawChar(font, str[i], x, y, color);
x += w;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/* /*
Palette is defined as follows: Palette is defined as follows:

View File

@ -22,7 +22,6 @@
#include <map> #include <map>
class FBSurface;
class OSystem; class OSystem;
class Console; class Console;
class Settings; class Settings;
@ -31,6 +30,7 @@ namespace GUI {
class Font; class Font;
} }
#include "FBSurface.hxx"
#include "EventHandler.hxx" #include "EventHandler.hxx"
#include "Rect.hxx" #include "Rect.hxx"
#include "StringList.hxx" #include "StringList.hxx"
@ -85,7 +85,6 @@ enum {
kNumColors kNumColors
}; };
/** /**
This class encapsulates all video buffers and is the basis for the video This class encapsulates all video buffers and is the basis for the video
display in Stella. All graphics ports should derive from this class for display in Stella. All graphics ports should derive from this class for
@ -646,234 +645,4 @@ class FrameBuffer
static uInt32 ourGUIColors[kNumColors-256]; static uInt32 ourGUIColors[kNumColors-256];
}; };
/**
This class is basically a thin wrapper around the video toolkit 'surface'
structure. We do it this way so the actual video toolkit won't be dragged
into the depths of the codebase. All drawing is done into FBSurfaces,
which are then drawn into the FrameBuffer. Each FrameBuffer-derived class
is responsible for extending an FBSurface object suitable to the
FrameBuffer type.
@author Stephen Anthony
@version $Id$
*/
// Text alignment modes for drawString()
enum TextAlignment {
kTextAlignLeft,
kTextAlignCenter,
kTextAlignRight
};
// Line types for drawing rectangular frames
enum FrameStyle {
kSolidLine,
kDashLine
};
class FBSurface
{
public:
/**
Creates a new FBSurface object
*/
FBSurface() { }
/**
Destructor
*/
virtual ~FBSurface() { }
/**
This method should be called to draw a horizontal line.
@param x The first x coordinate
@param y The y coordinate
@param x2 The second x coordinate
@param color The color of the line
*/
virtual void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { }
/**
This method should be called to draw a vertical line.
@param x The x coordinate
@param y The first y coordinate
@param y2 The second y coordinate
@param color The color of the line
*/
virtual void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { }
/**
This method should be called to draw a filled rectangle.
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
@param color
*/
virtual void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color) { }
/**
This method should be called to draw the specified character.
@param font The font to use to draw the character
@param c The character to draw
@param x The x coordinate
@param y The y coordinate
@param color The color of the character
*/
virtual void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y,
uInt32 color) { }
/**
This method should be called to draw the bitmap image.
@param bitmap The data to draw
@param x The x coordinate
@param y The y coordinate
@param color The color of the character
@param h The height of the data image
*/
virtual void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color,
uInt32 h = 8) { }
/**
This method should be called to convert and copy a given row of pixel
data into a FrameBuffer surface. The pixels must already be in the
format used by the surface.
@param data The data in uInt8 R/G/B format
@param row The row of the surface the data should be placed in
@param rowbytes The number of bytes in row of 'data'
*/
virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels) { }
/**
This method should be called copy the contents of the given
surface into the FrameBuffer surface.
@param surface The data to draw
@param x The x coordinate
@param y The y coordinate
*/
virtual void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y) { }
/**
This method should be called to add a dirty rectangle
(ie, an area of the screen that has changed)
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
*/
virtual void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { }
/**
This method answers the current position of the surface.
*/
virtual void getPos(uInt32& x, uInt32& y) const { }
/**
This method should be called to set the position of the surface.
*/
virtual void setPos(uInt32 x, uInt32 y) { }
/**
This method answers the current dimensions of the surface.
*/
virtual uInt32 getWidth() const { return 0; }
virtual uInt32 getHeight() const { return 0; }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setWidth(uInt32 w) { }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setHeight(uInt32 h) { }
/**
This method should be called to translate the given coordinates
to the surface coordinates.
@param x X coordinate to translate
@param y Y coordinate to translate
*/
virtual void translateCoords(Int32& x, Int32& y) const { }
/**
This method should be called to draw the surface to the screen.
*/
virtual void update() { }
/**
This method should be called to reset the surface to empty
pixels / colour black.
*/
virtual void invalidate() { }
/**
This method should be called to free any resources being used by
the surface.
*/
virtual void free() { }
/**
This method should be called to reload the surface data/state.
It will normally be called after free().
*/
virtual void reload() { }
/**
This method 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
@param colorA Lighter color for outside line.
@param colorB Darker color for inside line.
*/
virtual void box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB);
/**
This method should be called to draw a framed rectangle.
I'm not exactly sure what it is, so I can't explain it :)
@param x The x coordinate
@param y The y coordinate
@param w The width of the area
@param h The height of the area
@param color The color of the surrounding frame
*/
virtual void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style = kSolidLine);
/**
This method should be called to draw the specified string.
@param font The font to draw the string with
@param str The string to draw
@param x The x coordinate
@param y The y coordinate
@param w The width of the string area
@param h The height of the string area
@param color The color of the text
@param align The alignment of the text in the string width area
@param deltax
@param useEllipsis Whether to use '...' when the string is too long
*/
virtual void drawString(
const GUI::Font& font, const string& str, int x, int y, int w,
uInt32 color, TextAlignment align = kTextAlignLeft,
int deltax = 0, bool useEllipsis = true);
};
#endif #endif

View File

@ -45,6 +45,7 @@ MODULE_OBJS := \
src/emucore/Driving.o \ src/emucore/Driving.o \
src/emucore/EventHandler.o \ src/emucore/EventHandler.o \
src/emucore/FrameBuffer.o \ src/emucore/FrameBuffer.o \
src/emucore/FBSurface.o \
src/emucore/FSNode.o \ src/emucore/FSNode.o \
src/emucore/Genesis.o \ src/emucore/Genesis.o \
src/emucore/Joystick.o \ src/emucore/Joystick.o \