aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorPaul Gilbert2016-03-20 14:49:30 -0400
committerPaul Gilbert2016-03-20 14:49:30 -0400
commit509a00109e79156e91c062f145ac3aa86ec8584e (patch)
treee625fd93b3b21feabae1eff92e3efbf23a7d7a83 /graphics
parentf6c3363cf54af1c01efc12a98ab27a8af52aad3e (diff)
parent390487aa43e5507d4d0fb4ae57e7cf726a94f4c1 (diff)
downloadscummvm-rg350-509a00109e79156e91c062f145ac3aa86ec8584e.tar.gz
scummvm-rg350-509a00109e79156e91c062f145ac3aa86ec8584e.tar.bz2
scummvm-rg350-509a00109e79156e91c062f145ac3aa86ec8584e.zip
Merge pull request #652 from dreammaster/screen
ALL: Removing code duplication via new managed surface & screen classes
Diffstat (limited to 'graphics')
-rw-r--r--graphics/font.cpp11
-rw-r--r--graphics/font.h3
-rw-r--r--graphics/managed_surface.cpp260
-rw-r--r--graphics/managed_surface.h376
-rw-r--r--graphics/module.mk2
-rw-r--r--graphics/screen.cpp129
-rw-r--r--graphics/screen.h118
7 files changed, 899 insertions, 0 deletions
diff --git a/graphics/font.cpp b/graphics/font.cpp
index dba48249bc..d709758948 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -21,6 +21,7 @@
*/
#include "graphics/font.h"
+#include "graphics/managed_surface.h"
#include "common/array.h"
#include "common/util.h"
@@ -273,6 +274,16 @@ void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y,
drawStringImpl(*this, dst, str, x, y, w, color, align, 0);
}
+void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+ drawString(&dst->_innerSurface, str, x, y, w, color, align, deltax, useEllipsis);
+ dst->addDirtyRect(Common::Rect(x, y, x + w, y + getFontHeight()));
+}
+
+void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const {
+ drawString(&dst->_innerSurface, str, x, y, w, color, align);
+ dst->addDirtyRect(Common::Rect(x, y, x + w, y + getFontHeight()));
+}
+
int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const {
return wordWrapTextImpl(*this, str, maxWidth, lines);
}
diff --git a/graphics/font.h b/graphics/font.h
index 35f6792d7f..62e71a8568 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -34,6 +34,7 @@ template<class T> class Array;
namespace Graphics {
struct Surface;
+class ManagedSurface;
/** Text alignment modes */
enum TextAlign {
@@ -145,6 +146,8 @@ public:
// TODO: Add doxygen comments to this
void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const;
+ void drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
+ void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const;
/**
* Compute and return the width the string str has when rendered using this font.
diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp
new file mode 100644
index 0000000000..e493ab9f4e
--- /dev/null
+++ b/graphics/managed_surface.cpp
@@ -0,0 +1,260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/managed_surface.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
+
+namespace Graphics {
+
+const int SCALE_THRESHOLD = 0x100;
+
+ManagedSurface::ManagedSurface() :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+}
+
+ManagedSurface::ManagedSurface(const ManagedSurface &surf) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ *this = surf;
+}
+
+ManagedSurface::ManagedSurface(int width, int height) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(width, height);
+}
+
+ManagedSurface::ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(width, height, format);
+}
+
+ManagedSurface::ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(surf, bounds);
+}
+
+ManagedSurface::~ManagedSurface() {
+ free();
+}
+
+ManagedSurface &ManagedSurface::operator=(const ManagedSurface &surf) {
+ // Free any current surface
+ free();
+
+ if (surf._disposeAfterUse == DisposeAfterUse::YES) {
+ // Create a new surface and copy the pixels from the source surface
+ create(surf.w, surf.h, surf.format);
+ Common::copy((const byte *)surf.getPixels(), (const byte *)surf.getPixels() +
+ surf.w * surf.h * surf.format.bytesPerPixel, (byte *)this->getPixels());
+ } else {
+ // Source isn't managed, so simply copy its fields
+ _owner = surf._owner;
+ _offsetFromOwner = surf._offsetFromOwner;
+ void *srcPixels = (void *)surf._innerSurface.getPixels();
+ _innerSurface.setPixels(srcPixels);
+ _innerSurface.w = surf.w;
+ _innerSurface.h = surf.h;
+ _innerSurface.pitch = surf.pitch;
+ this->format = surf.format;
+ }
+
+ return *this;
+}
+
+void ManagedSurface::setPixels(void *newPixels) {
+ free();
+ _innerSurface.setPixels(newPixels);
+}
+
+void ManagedSurface::create(uint16 width, uint16 height) {
+ create(width, height, PixelFormat::createFormatCLUT8());
+}
+
+void ManagedSurface::create(uint16 width, uint16 height, const PixelFormat &pixelFormat) {
+ free();
+ _innerSurface.create(width, height, pixelFormat);
+
+ _disposeAfterUse = DisposeAfterUse::YES;
+ markAllDirty();
+}
+
+void ManagedSurface::create(ManagedSurface &surf, const Common::Rect &bounds) {
+ free();
+
+ _offsetFromOwner = Common::Point(bounds.left, bounds.top);
+ _innerSurface.setPixels(surf.getBasePtr(bounds.left, bounds.top));
+ _innerSurface.pitch = surf.pitch;
+ _innerSurface.format = surf.format;
+ _innerSurface.w = bounds.width();
+ _innerSurface.h = bounds.height();
+ _owner = &surf;
+ _disposeAfterUse = DisposeAfterUse::NO;
+}
+
+void ManagedSurface::free() {
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ _innerSurface.free();
+
+ _disposeAfterUse = DisposeAfterUse::NO;
+ _owner = nullptr;
+ _offsetFromOwner = Common::Point(0, 0);
+}
+
+bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) {
+ if (destBounds.left >= this->w || destBounds.top >= this->h ||
+ destBounds.right <= 0 || destBounds.bottom <= 0)
+ return false;
+
+ // Clip the bounds if necessary to fit on-screen
+ if (destBounds.right > this->w) {
+ srcBounds.right -= destBounds.right - this->w;
+ destBounds.right = this->w;
+ }
+
+ if (destBounds.bottom > this->h) {
+ srcBounds.bottom -= destBounds.bottom - this->h;
+ destBounds.bottom = this->h;
+ }
+
+ if (destBounds.top < 0) {
+ srcBounds.top += -destBounds.top;
+ destBounds.top = 0;
+ }
+
+ if (destBounds.left < 0) {
+ srcBounds.left += -destBounds.left;
+ destBounds.left = 0;
+ }
+
+ return true;
+}
+
+void ManagedSurface::blitFrom(const Surface &src) {
+ blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0));
+}
+
+void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) {
+ blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos);
+}
+
+void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos) {
+ Common::Rect srcBounds = srcRect;
+ Common::Rect destBounds(destPos.x, destPos.y, destPos.x + srcRect.width(),
+ destPos.y + srcRect.height());
+ assert(src.format.bytesPerPixel == format.bytesPerPixel);
+
+ if (!srcRect.isValidRect() || !clip(srcBounds, destBounds))
+ return;
+
+ for (int y = 0; y < srcBounds.height(); ++y) {
+ const byte *srcP = (const byte *)src.getBasePtr(srcBounds.left, srcBounds.top + y);
+ byte *destP = (byte *)getBasePtr(destBounds.left, destBounds.top + y);
+ Common::copy(srcP, srcP + srcBounds.width() * format.bytesPerPixel, destP);
+ }
+
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h),
+ transColor, false, overrideColor);
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos,
+ uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y,
+ destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y,
+ destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
+}
+
+template<typename T>
+void transBlit(const Surface &src, const Common::Rect &srcRect, const Surface *dest, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) {
+ int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width();
+ int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height();
+
+ // Loop through drawing output lines
+ for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) {
+ if (destY < 0 || destY >= dest->h)
+ continue;
+ const T *srcLine = (const T *)src.getBasePtr(0, scaleYCtr / SCALE_THRESHOLD);
+ T *destLine = (T *)dest->getBasePtr(destRect.left, destY);
+
+ // Loop through drawing the pixels of the row
+ for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) {
+ if (destX < 0 || destX >= dest->w)
+ continue;
+
+ T srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD];
+ if (srcVal != transColor) {
+ destLine[xCtr] = overrideColor ? overrideColor : srcVal;
+ }
+ }
+ }
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) {
+ if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0)
+ return;
+
+ if (format.bytesPerPixel == 1)
+ transBlit<byte>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else if (format.bytesPerPixel == 2)
+ transBlit<uint16>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else if (format.bytesPerPixel == 4)
+ transBlit<uint32>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else
+ error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4");
+
+ // Mark the affected area
+ addDirtyRect(destRect);
+}
+
+void ManagedSurface::markAllDirty() {
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void ManagedSurface::addDirtyRect(const Common::Rect &r) {
+ if (_owner) {
+ Common::Rect bounds = r;
+ bounds.clip(Common::Rect(0, 0, this->w, this->h));
+ bounds.translate(_offsetFromOwner.x, _offsetFromOwner.y);
+ _owner->addDirtyRect(bounds);
+ }
+}
+
+void ManagedSurface::clear(uint color) {
+ fillRect(getBounds(), color);
+}
+
+} // End of namespace Graphics
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
new file mode 100644
index 0000000000..bd0632a493
--- /dev/null
+++ b/graphics/managed_surface.h
@@ -0,0 +1,376 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GRAPHICS_MANAGED_SURFACE_H
+#define GRAPHICS_MANAGED_SURFACE_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+#include "common/rect.h"
+#include "common/types.h"
+
+namespace Graphics {
+
+class Font;
+
+/**
+ * A derived graphics surface, which handles automatically managing the allocated
+ * surface data block, as well as introducing several new blitting methods
+ */
+class ManagedSurface {
+ friend class Font;
+private:
+ /**
+ * The Graphics::Surface that the managed surface encapsulates
+ */
+ Surface _innerSurface;
+
+ /**
+ * If set, the inner surface will be freed when the surface is recreated,
+ * as well as when the surface is destroyed
+ */
+ DisposeAfterUse::Flag _disposeAfterUse;
+
+ /**
+ * Stores the owning surface if this If this managed surface represents
+ * a sub-section of another
+ */
+ ManagedSurface *_owner;
+
+ /**
+ * For sub-section areas of an owning parent managed surface, this represents
+ * the offset from the parent's top-left corner this sub-surface starts at
+ */
+ Common::Point _offsetFromOwner;
+protected:
+ /**
+ * Clips the given source bounds so the passed destBounds will be entirely on-screen
+ */
+ bool clip(Common::Rect &srcBounds, Common::Rect &destBounds);
+
+ /**
+ * Base method that descendent classes can override for recording affected
+ * dirty areas of the surface
+ */
+ virtual void addDirtyRect(const Common::Rect &r);
+public:
+ uint16 &w;
+ uint16 &h;
+ uint16 &pitch;
+ PixelFormat &format;
+public:
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface();
+
+ /**
+ * Create a managed surface from another one.
+ * If the source surface is maintaining it's own surface data, then
+ * this surface will create it's own surface of the same size and copy
+ * the contents from the source surface
+ */
+ ManagedSurface(const ManagedSurface &surf);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(int width, int height);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds);
+
+ /**
+ * Destroy the managed surface
+ */
+ virtual ~ManagedSurface();
+
+ /**
+ * Implements automatic conversion to a Graphics::Surface by
+ * simply returning the inner surface. This must be const,
+ * because we don't want changes being done directly to it,
+ * since it would bypass dirty rect handling
+ */
+ operator const Surface &() const { return _innerSurface; }
+ const Surface &rawSurface() const { return _innerSurface; }
+
+ /**
+ * Reassign one managed surface to another one
+ * Note that if the source has a managed surface, it will be duplicated
+ */
+ ManagedSurface &operator=(const ManagedSurface &surf);
+
+ /**
+ * Returns true if the surface has not yet been allocated
+ */
+ bool empty() const { return w == 0 || h == 0 || _innerSurface.getPixels() == nullptr; }
+
+ /**
+ * Returns true if the surface is managing its own pixels
+ */
+ DisposeAfterUse::Flag disposeAfterUse() const { return _disposeAfterUse; }
+
+ /**
+ * Return a pointer to the pixel at the specified point.
+ *
+ * @param x The x coordinate of the pixel.
+ * @param y The y coordinate of the pixel.
+ * @return Pointer to the pixel.
+ */
+ inline const void *getBasePtr(int x, int y) const {
+ return _innerSurface.getBasePtr(x, y);
+ }
+
+ /**
+ * Return a pointer to the pixel at the specified point.
+ *
+ * @param x The x coordinate of the pixel.
+ * @param y The y coordinate of the pixel.
+ * @return Pointer to the pixel.
+ */
+ inline void *getBasePtr(int x, int y) {
+ return _innerSurface.getBasePtr(x, y);
+ }
+
+ /**
+ * Get a reference to the pixel data
+ */
+ inline void *getPixels() { return _innerSurface.getPixels(); }
+ inline const void *getPixels() const { return _innerSurface.getPixels(); }
+
+ /**
+ * Sets the pixel data.
+ */
+ virtual void setPixels(void *newPixels);
+
+ /**
+ * Allocate memory for the pixel data of the surface.
+ */
+ virtual void create(uint16 width, uint16 height);
+
+ /**
+ * Allocate memory for the pixel data of the surface.
+ */
+ virtual void create(uint16 width, uint16 height, const PixelFormat &pixelFormat);
+
+ /**
+ * Sets up the surface as a sub-section of another passed parent surface. This surface
+ * will not own the pixels, and any dirty rect notifications will automatically be
+ * passed to the original parent surface.
+ * @remarks Note that this differs from Graphics::Surface::getSubArea, in that that
+ * method only adds a single initial dirty rect for the whole area, and then none further
+ */
+ virtual void create(ManagedSurface &surf, const Common::Rect &bounds);
+
+ /**
+ * Release the memory used by the pixels memory of this surface. This is the
+ * counterpart to create().
+ */
+ virtual void free();
+
+ /**
+ * Clears any pending dirty rects that have been generated for the surface
+ */
+ virtual void clearDirtyRects() {}
+
+ /**
+ * When the managed surface is a sub-section of a parent surface, returns the
+ * the offset in the parent surface that the surface starts at
+ */
+ const Common::Point getOffsetFromOwner() const { return _offsetFromOwner; }
+
+ /**
+ * Return a rect giving the bounds of the surface
+ */
+ const Common::Rect getBounds() const {
+ return Common::Rect(0, 0, this->w, this->h);
+ }
+
+ /**
+ * Copies another surface into this one
+ */
+ void blitFrom(const Surface &src);
+
+ /**
+ * Copies another surface into this one at a given destination position
+ */
+ void blitFrom(const Surface &src, const Common::Point &destPos);
+
+ /**
+ * Copies another surface into this one at a given destination position
+ */
+ void blitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param destPos Destination position to draw the surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Point &destPos,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param srcRect Sub-section of source surface to draw
+ * @param destPos Destination position to draw the surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param srcRect Sub-section of source surface to draw
+ * @param destRect Destination area to draw the surface in. This can be sized differently
+ * then srcRect, allowing for arbitrary scaling of the image
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Clear the entire surface
+ */
+ void clear(uint color = 0);
+
+ /**
+ * Mark the entire surface as dirty
+ */
+ void markAllDirty();
+
+ /**
+ * Copies a bitmap to the Surface internal buffer. The pixel format
+ * of buffer must match the pixel format of the Surface.
+ */
+ void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
+ _innerSurface.copyRectToSurface(buffer, srcPitch, destX, destY, width, height);
+ }
+
+ /**
+ * Copies a bitmap to the Surface internal buffer. The pixel format
+ * of buffer must match the pixel format of the Surface.
+ */
+ void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect) {
+ _innerSurface.copyRectToSurface(srcSurface, destX, destY, subRect);
+ }
+
+ /**
+ * Copy the data from another Surface, reinitializing the
+ * surface to match the dimensions of the passed surface
+ */
+ void copyFrom(const ManagedSurface &surf) {
+ clearDirtyRects();
+ _innerSurface.copyFrom(surf._innerSurface);
+ }
+
+ /**
+ * Draw a line.
+ */
+ void drawLine(int x0, int y0, int x1, int y1, uint32 color) {
+ _innerSurface.drawLine(x0, y0, x1, y1, color);
+ addDirtyRect(Common::Rect(x0, y0, x1, y1));
+ }
+
+ /**
+ * Draw a thick line.
+ */
+ void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color) {
+ _innerSurface.drawThickLine(x0, y0, x1, y1, penX, penY, color);
+ addDirtyRect(Common::Rect(x0, y0, x1 + penX, y1 + penY));
+ }
+
+ /**
+ * Draw a horizontal line.
+ */
+ void hLine(int x, int y, int x2, uint32 color) {
+ _innerSurface.hLine(x, y, x2, color);
+ addDirtyRect(Common::Rect(x, y, x2 + 1, y + 1));
+ }
+
+ /**
+ * Draw a vertical line.
+ */
+ void vLine(int x, int y, int y2, uint32 color) {
+ _innerSurface.vLine(x, y, y2, color);
+ addDirtyRect(Common::Rect(x, y, x + 1, y2 + 1));
+ }
+
+ /**
+ * Fill a rect with a given color.
+ */
+ void fillRect(Common::Rect r, uint32 color) {
+ _innerSurface.fillRect(r, color);
+ addDirtyRect(r);
+ }
+
+ /**
+ * Draw a frame around a specified rect.
+ */
+ void frameRect(const Common::Rect &r, uint32 color) {
+ _innerSurface.frameRect(r, color);
+ addDirtyRect(r);
+ }
+
+ /**
+ * Returns a sub-area of the screen, but only adds a single initial dirty rect
+ * for the retrieved area.
+ */
+ Surface getSubArea(const Common::Rect &area) {
+ addDirtyRect(area);
+ return _innerSurface.getSubArea(area);
+ }
+};
+
+} // End of namespace Graphics
+
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index b6919cf1ab..90f6a3199c 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -12,10 +12,12 @@ MODULE_OBJS := \
fonts/ttf.o \
fonts/winfont.o \
maccursor.o \
+ managed_surface.o \
pixelformat.o \
primitives.o \
scaler.o \
scaler/thumbnail_intern.o \
+ screen.o \
sjis.o \
surface.o \
transform_struct.o \
diff --git a/graphics/screen.cpp b/graphics/screen.cpp
new file mode 100644
index 0000000000..4169c98035
--- /dev/null
+++ b/graphics/screen.cpp
@@ -0,0 +1,129 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "common/algorithm.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+
+namespace Graphics {
+
+Screen::Screen(): ManagedSurface() {
+ create(g_system->getWidth(), g_system->getHeight());
+}
+
+Screen::Screen(int width, int height): ManagedSurface() {
+ create(width, height);
+}
+
+Screen::Screen(int width, int height, PixelFormat pixelFormat): ManagedSurface() {
+ create(width, height, pixelFormat);
+}
+
+void Screen::update() {
+ // Merge the dirty rects
+ mergeDirtyRects();
+
+ // Loop through copying dirty areas to the physical screen
+ Common::List<Common::Rect>::iterator i;
+ for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
+ const Common::Rect &r = *i;
+ const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
+ g_system->copyRectToScreen(srcP, pitch, r.left, r.top,
+ r.width(), r.height());
+ }
+
+ // Signal the physical screen to update
+ g_system->updateScreen();
+ _dirtyRects.clear();
+}
+
+
+void Screen::addDirtyRect(const Common::Rect &r) {
+ Common::Rect bounds = r;
+ bounds.clip(getBounds());
+ bounds.translate(getOffsetFromOwner().x, getOffsetFromOwner().y);
+
+ if (bounds.width() > 0 && bounds.height() > 0)
+ _dirtyRects.push_back(bounds);
+}
+
+void Screen::makeAllDirty() {
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void Screen::mergeDirtyRects() {
+ Common::List<Common::Rect>::iterator rOuter, rInner;
+
+ // Process the dirty rect list to find any rects to merge
+ for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
+ rInner = rOuter;
+ while (++rInner != _dirtyRects.end()) {
+
+ if ((*rOuter).intersects(*rInner)) {
+ // These two rectangles overlap, so merge them
+ unionRectangle(*rOuter, *rOuter, *rInner);
+
+ // remove the inner rect from the list
+ _dirtyRects.erase(rInner);
+
+ // move back to beginning of list
+ rInner = rOuter;
+ }
+ }
+ }
+}
+
+bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
+ destRect = src1;
+ destRect.extend(src2);
+
+ return !destRect.isEmpty();
+}
+
+void Screen::getPalette(byte palette[PALETTE_SIZE]) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
+}
+
+void Screen::getPalette(byte *palette, uint start, uint num) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->grabPalette(palette, start, num);
+}
+
+void Screen::setPalette(const byte palette[PALETTE_SIZE]) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT);
+}
+
+void Screen::setPalette(const byte *palette, uint start, uint num) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->setPalette(palette, start, num);
+}
+
+void Screen::clearPalette() {
+ byte palette[PALETTE_SIZE];
+ Common::fill(&palette[0], &palette[PALETTE_SIZE], 0);
+ setPalette(palette);
+}
+
+} // End of namespace Graphics
diff --git a/graphics/screen.h b/graphics/screen.h
new file mode 100644
index 0000000000..29816120f1
--- /dev/null
+++ b/graphics/screen.h
@@ -0,0 +1,118 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GRAPHICS_SCREEN_H
+#define GRAPHICS_SCREEN_H
+
+#include "graphics/managed_surface.h"
+#include "graphics/pixelformat.h"
+#include "common/list.h"
+#include "common/rect.h"
+
+namespace Graphics {
+
+#define PALETTE_COUNT 256
+#define PALETTE_SIZE (256 * 3)
+
+/**
+ * Implements a specialised surface that represents the screen.
+ * It keeps track of any areas of itself that are updated by drawing
+ * calls, and provides an update that method that blits the affected
+ * areas to the physical screen
+ */
+class Screen : virtual public ManagedSurface {
+private:
+ /**
+ * List of affected areas of the screen
+ */
+ Common::List<Common::Rect> _dirtyRects;
+private:
+ /**
+ * Merges together overlapping dirty areas of the screen
+ */
+ void mergeDirtyRects();
+
+ /**
+ * Returns the union of two dirty area rectangles
+ */
+ bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
+protected:
+ /**
+ * Adds a rectangle to the list of modified areas of the screen during the
+ * current frame
+ */
+ virtual void addDirtyRect(const Common::Rect &r);
+public:
+ Screen();
+ Screen(int width, int height);
+ Screen(int width, int height, PixelFormat pixelFormat);
+
+ /**
+ * Returns true if there are any pending screen updates (dirty areas)
+ */
+ bool isDirty() const { return !_dirtyRects.empty(); }
+
+ /**
+ * Marks the whole screen as dirty. This forces the next call to update
+ * to copy the entire screen contents
+ */
+ void makeAllDirty();
+
+ /**
+ * Clear the current dirty rects list
+ */
+ virtual void clearDirtyRects() { _dirtyRects.clear(); }
+
+ /**
+ * Updates the screen by copying any affected areas to the system
+ */
+ virtual void update();
+
+ /**
+ * Return the currently active palette
+ */
+ void getPalette(byte palette[PALETTE_SIZE]);
+
+ /**
+ * Return a portion of the currently active palette
+ */
+ void getPalette(byte *palette, uint start, uint num);
+
+ /**
+ * Set the palette
+ */
+ void setPalette(const byte palette[PALETTE_SIZE]);
+
+ /**
+ * Set a subsection of the palette
+ */
+ void setPalette(const byte *palette, uint start, uint num);
+
+ /**
+ * Clears the current palette, setting all entries to black
+ */
+ void clearPalette();
+};
+
+} // End of namespace Graphics
+
+#endif