aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/cursorman.cpp7
-rw-r--r--graphics/cursorman.h6
-rw-r--r--graphics/scaler.h6
-rw-r--r--graphics/scaler/thumbnail_intern.cpp32
-rw-r--r--graphics/thumbnail.cpp118
-rw-r--r--graphics/thumbnail.h18
-rw-r--r--graphics/yuv_to_rgb.h15
7 files changed, 186 insertions, 16 deletions
diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp
index c818101645..6825767dfd 100644
--- a/graphics/cursorman.cpp
+++ b/graphics/cursorman.cpp
@@ -48,6 +48,9 @@ bool CursorManager::isVisible() {
bool CursorManager::showMouse(bool visible) {
if (_cursorStack.empty())
return false;
+ if (_locked) {
+ return false;
+ }
_cursorStack.top()->_visible = visible;
@@ -225,6 +228,10 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu
}
}
+void CursorManager::lock(bool locked) {
+ _locked = locked;
+}
+
CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
#ifdef USE_RGB_COLOR
if (!format)
diff --git a/graphics/cursorman.h b/graphics/cursorman.h
index 66e8d1ba56..b4d8ad94ce 100644
--- a/graphics/cursorman.h
+++ b/graphics/cursorman.h
@@ -160,12 +160,15 @@ public:
*/
void replaceCursorPalette(const byte *colors, uint start, uint num);
+ void lock(bool locked);
private:
friend class Common::Singleton<SingletonBaseType>;
// Even though this is basically the default constructor we implement it
// ourselves, so it is private and thus there is no way to create this class
// except from the Singleton code.
- CursorManager() {}
+ CursorManager() {
+ _locked = false;
+ }
~CursorManager();
struct Cursor {
@@ -198,6 +201,7 @@ private:
};
Common::Stack<Cursor *> _cursorStack;
Common::Stack<Palette *> _cursorPaletteStack;
+ bool _locked;
};
} // End of namespace Graphics
diff --git a/graphics/scaler.h b/graphics/scaler.h
index 1e5b796631..54d022d202 100644
--- a/graphics/scaler.h
+++ b/graphics/scaler.h
@@ -89,4 +89,10 @@ extern bool createThumbnailFromScreen(Graphics::Surface *surf);
*/
extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette);
+/**
+ * Downscale screenshot to thumbnale size.
+ *
+ */
+extern bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in);
+
#endif
diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp
index 88f3cc2077..8a98263eee 100644
--- a/graphics/scaler/thumbnail_intern.cpp
+++ b/graphics/scaler/thumbnail_intern.cpp
@@ -134,7 +134,7 @@ static bool grabScreen565(Graphics::Surface *surf) {
return true;
}
-static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
+bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
uint16 width = in.w;
uint16 inHeight = in.h;
@@ -206,7 +206,7 @@ static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
return true;
}
-bool createThumbnailFromScreen(Graphics::Surface* surf) {
+bool createThumbnailFromScreen(Graphics::Surface *surf) {
assert(surf);
Graphics::Surface screen;
@@ -236,3 +236,31 @@ bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h,
return createThumbnail(*surf, screen);
}
+
+// this is somewhat awkward, but createScreenShot should logically be in graphics,
+// but moving other functions in this file into that namespace breaks several engines
+namespace Graphics {
+bool createScreenShot(Graphics::Surface &surf) {
+ Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
+ //convert surface to 2 bytes pixel format to avoid problems with palette saving and loading
+ if ((screenFormat.bytesPerPixel == 1) || (screenFormat.bytesPerPixel == 2)) {
+ return grabScreen565(&surf);
+ } else {
+ Graphics::Surface *screen = g_system->lockScreen();
+ if (!screen) {
+ return false;
+ }
+ surf.create(screen->w, screen->h, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+ for (uint y = 0; y < screen->h; ++y) {
+ for (uint x = 0; x < screen->w; ++x) {
+ byte r = 0, g = 0, b = 0, a = 0;
+ uint32 col = READ_UINT32(screen->getBasePtr(x, y));
+ screenFormat.colorToARGB(col, a, r, g, b);
+ ((uint32 *)surf.pixels)[y * surf.w + x] = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(a, r, g, b);
+ }
+ }
+ g_system->unlockScreen();
+ return true;
+ }
+}
+} // End of namespace Graphics
diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp
index ddb377306d..e3f368dffa 100644
--- a/graphics/thumbnail.cpp
+++ b/graphics/thumbnail.cpp
@@ -23,6 +23,7 @@
#include "graphics/scaler.h"
#include "graphics/colormasks.h"
#include "common/endian.h"
+#include "common/algorithm.h"
#include "common/system.h"
#include "common/stream.h"
#include "common/textconsole.h"
@@ -42,7 +43,16 @@ struct ThumbnailHeader {
#define ThumbnailHeaderSize (4+4+1+2+2+(1+4+4))
-bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) {
+enum HeaderState {
+ /// There is no header present
+ kHeaderNone,
+ /// The header present only has reliable values for version and size
+ kHeaderUnsupported,
+ /// The header is present and the version is supported
+ kHeaderPresent
+};
+
+HeaderState loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) {
header.type = in.readUint32BE();
// We also accept the bad 'BMHT' header here, for the sake of compatibility
// with some older savegames which were written incorrectly due to a bug in
@@ -50,16 +60,28 @@ bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool ou
if (header.type != MKTAG('T','H','M','B') && header.type != MKTAG('B','M','H','T')) {
if (outputWarnings)
warning("couldn't find thumbnail header type");
- return false;
+ return kHeaderNone;
}
header.size = in.readUint32BE();
header.version = in.readByte();
+ // Do a check whether any read errors had occured. If so we cannot use the
+ // values obtained for size and version because they might be bad.
+ if (in.err() || in.eos()) {
+ // TODO: We fake that there is no header. This is actually not quite
+ // correct since we found the start of the header and then things
+ // started to break. Right no we leave detection of this to the client.
+ // Since this case is caused by broken files, the client code should
+ // catch it anyway... If there is a nicer solution here, we should
+ // implement it.
+ return kHeaderNone;
+ }
+
if (header.version > THMB_VERSION) {
if (outputWarnings)
warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION);
- return false;
+ return kHeaderUnsupported;
}
header.width = in.readUint16BE();
@@ -81,7 +103,15 @@ bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool ou
header.format = createPixelFormat<565>();
}
- return true;
+ if (in.err() || in.eos()) {
+ // When we reached this point we know that at least the size and
+ // version field was loaded successfully, thus we tell this header
+ // is not supported and silently hope that the client code is
+ // prepared to handle read errors.
+ return kHeaderUnsupported;
+ } else {
+ return kHeaderPresent;
+ }
}
} // end of anonymous namespace
@@ -89,7 +119,12 @@ bool checkThumbnailHeader(Common::SeekableReadStream &in) {
uint32 position = in.pos();
ThumbnailHeader header;
- bool hasHeader = loadHeader(in, header, false);
+ // TODO: It is not clear whether this is the best semantics. Now
+ // checkThumbnailHeader will return true even when the thumbnail header
+ // found is actually not usable. However, most engines seem to use this
+ // to detect the presence of any header and if there is none it wont even
+ // try to skip it. Thus, this looks like the best solution for now...
+ bool hasHeader = (loadHeader(in, header, false) != kHeaderNone);
in.seek(position, SEEK_SET);
@@ -100,7 +135,9 @@ bool skipThumbnail(Common::SeekableReadStream &in) {
uint32 position = in.pos();
ThumbnailHeader header;
- if (!loadHeader(in, header, false)) {
+ // We can skip unsupported and supported headers. So we only seek back
+ // to the old position in case there is no header at all.
+ if (loadHeader(in, header, false) == kHeaderNone) {
in.seek(position, SEEK_SET);
return false;
}
@@ -110,10 +147,23 @@ bool skipThumbnail(Common::SeekableReadStream &in) {
}
Graphics::Surface *loadThumbnail(Common::SeekableReadStream &in) {
+ const uint32 position = in.pos();
ThumbnailHeader header;
-
- if (!loadHeader(in, header, true))
+ HeaderState headerState = loadHeader(in, header, true);
+
+ // Try to handle unsupported/broken headers gracefully. If there is no
+ // header at all, we seek back and return at this point. If there is an
+ // unsupported/broken header, we skip the actual data and return. The
+ // downside is that we might reset the end of stream flag with this and
+ // the client code would not be able to notice a read past the end of the
+ // stream at this point then.
+ if (headerState == kHeaderNone) {
+ in.seek(position, SEEK_SET);
+ return 0;
+ } else if (headerState == kHeaderUnsupported) {
+ in.seek(header.size - (in.pos() - position), SEEK_CUR);
return 0;
+ }
if (header.format.bytesPerPixel != 2 && header.format.bytesPerPixel != 4) {
warning("trying to load thumbnail with unsupported bit depth %d", header.format.bytesPerPixel);
@@ -143,7 +193,6 @@ Graphics::Surface *loadThumbnail(Common::SeekableReadStream &in) {
assert(0);
}
}
-
return to;
}
@@ -216,4 +265,55 @@ bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) {
return true;
}
+
+/**
+ * Returns an array indicating which pixels of a source image horizontally or vertically get
+ * included in a scaled image
+ */
+int *scaleLine(int size, int srcSize) {
+ int scale = 100 * size / srcSize;
+ assert(scale > 0);
+ int *v = new int[size];
+ Common::fill(v, &v[size], 0);
+
+ int distCtr = 0;
+ int *destP = v;
+ for (int distIndex = 0; distIndex < srcSize; ++distIndex) {
+ distCtr += scale;
+ while (distCtr >= 100) {
+ assert(destP < &v[size]);
+ *destP++ = distIndex;
+ distCtr -= 100;
+ }
+ }
+
+ return v;
+}
+
+Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize) {
+ Graphics::Surface *s = new Graphics::Surface();
+ s->create(xSize, ySize, srcImage.format);
+
+ int *horizUsage = scaleLine(xSize, srcImage.w);
+ int *vertUsage = scaleLine(ySize, srcImage.h);
+
+ // Loop to create scaled version
+ for (int yp = 0; yp < ySize; ++yp) {
+ const byte *srcP = (const byte *)srcImage.getBasePtr(0, vertUsage[yp]);
+ byte *destP = (byte *)s->getBasePtr(0, yp);
+
+ for (int xp = 0; xp < xSize; ++xp) {
+ const byte *tempSrcP = srcP + (horizUsage[xp] * srcImage.format.bytesPerPixel);
+ for (int byteCtr = 0; byteCtr < srcImage.format.bytesPerPixel; ++byteCtr) {
+ *destP++ = *tempSrcP++;
+ }
+ }
+ }
+
+ // Delete arrays and return surface
+ delete[] horizUsage;
+ delete[] vertUsage;
+ return s;
+}
+
} // End of namespace Graphics
diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h
index 45a0fdbf07..c857809c91 100644
--- a/graphics/thumbnail.h
+++ b/graphics/thumbnail.h
@@ -64,6 +64,24 @@ bool saveThumbnail(Common::WriteStream &out);
*/
bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb);
+/**
+ * Grabs framebuffer into surface
+ *
+ * @param surf a surface
+ * @return false if a error occurred
+ */
+bool createScreenShot(Graphics::Surface &surf);
+
+/**
+ * Scales a passed surface, creating a new surface with the result
+ * @param srcImage Source image to scale
+ * @param xSize New surface width
+ * @param ySize New surface height
+ * @remarks Caller is responsible for freeing the returned surface
+ */
+Graphics::Surface *scale(const Graphics::Surface &srcImage, int xSize, int ySize);
+
+
} // End of namespace Graphics
#endif
diff --git a/graphics/yuv_to_rgb.h b/graphics/yuv_to_rgb.h
index f785422c5a..a1e61ec705 100644
--- a/graphics/yuv_to_rgb.h
+++ b/graphics/yuv_to_rgb.h
@@ -22,10 +22,17 @@
/**
* @file
- * YUV to RGB conversion used in engines:
- * - mohawk
- * - scumm (he)
- * - sword25
+ * YUV to RGB conversion.
+ *
+ * Used in graphics:
+ * - JPEGDecoder
+ *
+ * Used in video:
+ * - BinkDecoder
+ * - Indeo3Decoder
+ * - PSXStreamDecoder
+ * - TheoraDecoder
+ * - SVQ1Decoder
*/
#ifndef GRAPHICS_YUV_TO_RGB_H