diff --git a/src/emucore/FBSurface.cxx b/src/emucore/FBSurface.cxx new file mode 100644 index 000000000..e162340a2 --- /dev/null +++ b/src/emucore/FBSurface.cxx @@ -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; + } +} diff --git a/src/emucore/FBSurface.hxx b/src/emucore/FBSurface.hxx new file mode 100644 index 000000000..4a4260fd7 --- /dev/null +++ b/src/emucore/FBSurface.hxx @@ -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 diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 5962d0e54..24b86d216 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -37,6 +37,7 @@ #include "Settings.hxx" #include "TIA.hxx" +#include "FBSurface.hxx" #include "FrameBuffer.hxx" #ifdef DEBUGGER_SUPPORT @@ -917,10 +918,11 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) ); } +#if 0 //FIXSDL cerr << "Windowed modes:\n" << myWindowedModeList << endl << "Fullscreen modes:\n" << myFullscreenModeList << endl << endl; - +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1108,137 +1110,6 @@ void FrameBuffer::VideoModeList::setZoom(uInt32 zoom) 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: diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index d9e0d14f5..7821e1eb6 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -22,7 +22,6 @@ #include -class FBSurface; class OSystem; class Console; class Settings; @@ -31,6 +30,7 @@ namespace GUI { class Font; } +#include "FBSurface.hxx" #include "EventHandler.hxx" #include "Rect.hxx" #include "StringList.hxx" @@ -85,7 +85,6 @@ enum { kNumColors }; - /** 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 @@ -646,234 +645,4 @@ class FrameBuffer 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 diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 7d754d4fc..57591721b 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -45,6 +45,7 @@ MODULE_OBJS := \ src/emucore/Driving.o \ src/emucore/EventHandler.o \ src/emucore/FrameBuffer.o \ + src/emucore/FBSurface.o \ src/emucore/FSNode.o \ src/emucore/Genesis.o \ src/emucore/Joystick.o \