aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/graphics
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2012-05-31 22:00:11 +0200
committerEinar Johan Trøan Sømåen2012-06-02 13:05:42 +0200
commitae48c3f7e156d2fd5dfd2dba8931cfee679c0198 (patch)
treeabaf7d9bd2708b2b5cfe80a01b0eedeff57e8cd3 /engines/wintermute/graphics
parenta53fa953a4869bed8e9aebe86ca6343e79225bf6 (diff)
downloadscummvm-rg350-ae48c3f7e156d2fd5dfd2dba8931cfee679c0198.tar.gz
scummvm-rg350-ae48c3f7e156d2fd5dfd2dba8931cfee679c0198.tar.bz2
scummvm-rg350-ae48c3f7e156d2fd5dfd2dba8931cfee679c0198.zip
WINTERMUTE: Add transparentSurface internally for now, to allow alpha-blended blits.
Diffstat (limited to 'engines/wintermute/graphics')
-rw-r--r--engines/wintermute/graphics/transparentSurface.cpp322
-rw-r--r--engines/wintermute/graphics/transparentSurface.h124
2 files changed, 446 insertions, 0 deletions
diff --git a/engines/wintermute/graphics/transparentSurface.cpp b/engines/wintermute/graphics/transparentSurface.cpp
new file mode 100644
index 0000000000..c8ac9f1a2c
--- /dev/null
+++ b/engines/wintermute/graphics/transparentSurface.cpp
@@ -0,0 +1,322 @@
+/* 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/algorithm.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/rect.h"
+#include "common/textconsole.h"
+#include "graphics/primitives.h"
+#include "engines/wintermute/graphics/transparentSurface.h"
+
+namespace WinterMute {
+
+TransparentSurface::TransparentSurface() : Surface() {}
+
+TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface() {
+ if (copyData) {
+ copyFrom(surf);
+ } else {
+ w = surf.w;
+ h = surf.h;
+ pitch = surf.pitch;
+ format = surf.format;
+ pixels = surf.pixels;
+ }
+}
+
+Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) {
+ int ca = (color >> 24) & 0xff;
+
+ Common::Rect retSize;
+ retSize.top = 0;
+ retSize.left = 0;
+ retSize.setWidth(0);
+ retSize.setHeight(0);
+ // Check if we need to draw anything at all
+ if (ca == 0)
+ return retSize;
+
+ int cr = (color >> 16) & 0xff;
+ int cg = (color >> 8) & 0xff;
+ int cb = (color >> 0) & 0xff;
+
+ // Compensate for transparency. Since we're coming
+ // down to 255 alpha, we just compensate for the colors here
+ if (ca != 255) {
+ cr = cr * ca >> 8;
+ cg = cg * ca >> 8;
+ cb = cb * ca >> 8;
+ }
+
+ // Create an encapsulating surface for the data
+ TransparentSurface srcImage(*this, false);
+ // TODO: Is the data really in the screen format?
+ if (format.bytesPerPixel != 4) {
+ error("TransparentSurface can only blit 32 bpp images");
+ }
+
+ if (pPartRect) {
+ srcImage.pixels = &((char *)pixels)[pPartRect->top * srcImage.pitch + pPartRect->left * 4];
+ srcImage.w = pPartRect->width();
+ srcImage.h = pPartRect->height();
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
+ pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
+ } else {
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
+ srcImage.w, srcImage.h, color, width, height);
+ }
+
+ if (width == -1)
+ width = srcImage.w;
+ if (height == -1)
+ height = srcImage.h;
+
+#ifdef SCALING_TESTING
+ // Hardcode scaling to 66% to test scaling
+ width = width * 2 / 3;
+ height = height * 2 / 3;
+#endif
+
+ Graphics::Surface *img;
+ Graphics::Surface *imgScaled = NULL;
+ byte *savedPixels = NULL;
+ if ((width != srcImage.w) || (height != srcImage.h)) {
+ // Scale the image
+ img = imgScaled = srcImage.scale(width, height);
+ savedPixels = (byte *)img->pixels;
+ } else {
+ img = &srcImage;
+ }
+
+ // Handle off-screen clipping
+ if (posY < 0) {
+ img->h = MAX(0, (int)img->h - -posY);
+ img->pixels = (byte *)img->pixels + img->pitch * -posY;
+ posY = 0;
+ }
+
+ if (posX < 0) {
+ img->w = MAX(0, (int)img->w - -posX);
+ img->pixels = (byte *)img->pixels + (-posX * 4);
+ posX = 0;
+ }
+
+ img->w = CLIP((int)img->w, 0, (int)MAX((int)target.w - posX, 0));
+ img->h = CLIP((int)img->h, 0, (int)MAX((int)target.h - posY, 0));
+
+ if ((img->w > 0) && (img->h > 0)) {
+ int xp = 0, yp = 0;
+
+ int inStep = 4;
+ int inoStep = img->pitch;
+ if (flipping & TransparentSurface::FLIP_V) {
+ inStep = -inStep;
+ xp = img->w - 1;
+ }
+
+ if (flipping & TransparentSurface::FLIP_H) {
+ inoStep = -inoStep;
+ yp = img->h - 1;
+ }
+
+ byte *ino = (byte *)img->getBasePtr(xp, yp);
+ byte *outo = (byte *)target.getBasePtr(posX, posY);
+ byte *in, *out;
+
+ int bShift = img->format.bShift;
+ int gShift = img->format.gShift;
+ int rShift = img->format.rShift;
+ int aShift = img->format.aShift;
+
+ int bShiftTarget = target.format.bShift;
+ int gShiftTarget = target.format.gShift;
+ int rShiftTarget = target.format.rShift;
+ int aShiftTarget = target.format.aShift;
+
+ for (int i = 0; i < img->h; i++) {
+ out = outo;
+ in = ino;
+ for (int j = 0; j < img->w; j++) {
+ uint32 pix = *(uint32 *)in;
+ uint32 o_pix = *(uint32 *) out;
+ int b = (pix >> bShift) & 0xff;
+ int g = (pix >> gShift) & 0xff;
+ int r = (pix >> rShift) & 0xff;
+ int a = (pix >> aShift) & 0xff;
+ int o_b, o_g, o_r, o_a;
+ in += inStep;
+
+ if (ca != 255) {
+ a = a * ca >> 8;
+ }
+
+ switch (a) {
+ case 0: // Full transparency
+ out += 4;
+ break;
+ case 255: // Full opacity
+ if (cb != 255)
+ o_b = (b * cb) >> 8;
+ else
+ o_b = b;
+
+ if (cg != 255)
+ o_g = (g * cg) >> 8;
+ else
+ o_g = g;
+
+ if (cr != 255)
+ o_r = (r * cr) >> 8;
+ else
+ o_r = r;
+ o_a = a;
+ *(uint32 *)out = target.format.ARGBToColor(o_a, o_r, o_g, o_b);
+ out += 4;
+ break;
+
+ default: // alpha blending
+ o_a = 255;
+ o_b = (o_pix >> bShiftTarget) & 0xff;
+ o_g = (o_pix >> gShiftTarget) & 0xff;
+ o_r = (o_pix >> rShiftTarget) & 0xff;
+ if (cb == 0)
+ o_b = 0;
+ else if (cb != 255)
+ o_b += ((b - o_b) * a * cb) >> 16;
+ else
+ o_b += ((b - o_b) * a) >> 8;
+ if (cg == 0)
+ o_g = 0;
+ else if (cg != 255)
+ o_g += ((g - o_g) * a * cg) >> 16;
+ else
+ o_g += ((g - o_g) * a) >> 8;
+ if (cr == 0)
+ o_r = 0;
+ else if (cr != 255)
+ o_r += ((r - o_r) * a * cr) >> 16;
+ else
+ o_r += ((r - o_r) * a) >> 8;
+ *(uint32 *)out = target.format.ARGBToColor(o_a, o_r, o_g, o_b);
+ out += 4;
+ }
+ }
+ outo += target.pitch;
+ ino += inoStep;
+ }
+ }
+
+ if (imgScaled) {
+ imgScaled->pixels = savedPixels;
+ imgScaled->free();
+ delete imgScaled;
+ }
+
+ retSize.setWidth(img->w);
+ retSize.setHeight(img->h);
+ return retSize;
+}
+
+/**
+ * Scales a passed surface, creating a new surface with the result
+ * @param srcImage Source image to scale
+ * @param scaleFactor Scale amount. Must be between 0 and 1.0 (but not zero)
+ * @remarks Caller is responsible for freeing the returned surface
+ */
+TransparentSurface *TransparentSurface::scale(int xSize, int ySize) const {
+ TransparentSurface *s = new TransparentSurface();
+ s->create(xSize, ySize, this->format);
+
+ int *horizUsage = scaleLine(xSize, this->w);
+ int *vertUsage = scaleLine(ySize, this->h);
+
+ // Loop to create scaled version
+ for (int yp = 0; yp < ySize; ++yp) {
+ const byte *srcP = (const byte *)this->getBasePtr(0, vertUsage[yp]);
+ byte *destP = (byte *)s->getBasePtr(0, yp);
+
+ for (int xp = 0; xp < xSize; ++xp) {
+ const byte *tempSrcP = srcP + (horizUsage[xp] * this->format.bytesPerPixel);
+ for (int byteCtr = 0; byteCtr < this->format.bytesPerPixel; ++byteCtr) {
+ *destP++ = *tempSrcP++;
+ }
+ }
+ }
+
+ // Delete arrays and return surface
+ delete[] horizUsage;
+ delete[] vertUsage;
+ return s;
+}
+
+/**
+ * Writes a color key to the alpha channel of the surface
+ * @param rKey the red component of the color key
+ * @param gKey the green component of the color key
+ * @param bKey the blue component of the color key
+ * @param overwriteAlpha if true, all other alpha will be set fully opaque
+ */
+void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) {
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ uint32 pix = ((uint32 *)pixels)[i * w + j];
+ uint8 r, g, b, a;
+ format.colorToARGB(pix, a, r, g, b);
+ if (r == rKey && g == gKey && b == bKey) {
+ a = 0;
+ ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
+ } else if (overwriteAlpha) {
+ a = 255;
+ ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
+ }
+ }
+ }
+}
+
+/**
+ * Returns an array indicating which pixels of a source image horizontally or vertically get
+ * included in a scaled image
+ */
+int *TransparentSurface::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;
+}
+
+
+} // End of namespace Graphics
diff --git a/engines/wintermute/graphics/transparentSurface.h b/engines/wintermute/graphics/transparentSurface.h
new file mode 100644
index 0000000000..e271bf2488
--- /dev/null
+++ b/engines/wintermute/graphics/transparentSurface.h
@@ -0,0 +1,124 @@
+/* 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_TRANSPARENTSURFACE_H
+#define GRAPHICS_TRANSPARENTSURFACE_H
+
+#include "graphics/surface.h"
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+// TODO: Find a better solution for this.
+#define BS_RGB(R,G,B) (0xFF000000 | ((R) << 16) | ((G) << 8) | (B))
+#define BS_ARGB(A,R,G,B) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B))
+
+namespace WinterMute {
+
+/**
+ * A transparent graphics surface, which implements alpha blitting.
+ */
+struct TransparentSurface : public Graphics::Surface {
+ TransparentSurface();
+ TransparentSurface(const Graphics::Surface &surf, bool copyData = false);
+
+ void setColorKey(char r, char g, char b);
+ void disableColorKey();
+
+ // Enums
+ /**
+ @brief The possible flipping parameters for the blit methode.
+ */
+ enum FLIP_FLAGS {
+ /// The image will not be flipped.
+ FLIP_NONE = 0,
+ /// The image will be flipped at the horizontal axis.
+ FLIP_H = 1,
+ /// The image will be flipped at the vertical axis.
+ FLIP_V = 2,
+ /// The image will be flipped at the horizontal and vertical axis.
+ FLIP_HV = FLIP_H | FLIP_V,
+ /// The image will be flipped at the horizontal and vertical axis.
+ FLIP_VH = FLIP_H | FLIP_V
+ };
+
+ /**
+ @brief renders the surface to another surface
+ @param pDest a pointer to the target image. In most cases this is the framebuffer.
+ @param PosX the position on the X-axis in the target image in pixels where the image is supposed to be rendered.<br>
+ The default value is 0.
+ @param PosY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br>
+ The default value is 0.
+ @param Flipping how the the image should be flipped.<br>
+ The default value is BS_Image::FLIP_NONE (no flipping)
+ @param pSrcPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br>
+ This referes to the unflipped and unscaled image.<br>
+ The default value is NULL.
+ @param Color an ARGB color value, which determines the parameters for the color modulation und alpha blending.<br>
+ The alpha component of the color determines the alpha blending parameter (0 = no covering, 255 = full covering).<br>
+ The color components determines the color for color modulation.<br>
+ The default value is BS_ARGB(255, 255, 255, 255) (full covering, no color modulation).
+ The macros BS_RGB and BS_ARGB can be used for the creation of the color value.
+ @param Width the output width of the screen section.
+ The images will be scaled if the output width of the screen section differs from the image section.<br>
+ The value -1 determines that the image should not be scaled.<br>
+ The default value is -1.
+ @param Width the output height of the screen section.
+ The images will be scaled if the output width of the screen section differs from the image section.<br>
+ The value -1 determines that the image should not be scaled.<br>
+ The default value is -1.
+ @return returns false if the rendering failed.
+ */
+
+ Common::Rect blit(Graphics::Surface &target, int posX = 0, int posY = 0,
+ int flipping = FLIP_NONE,
+ Common::Rect *pPartRect = NULL,
+ uint color = BS_ARGB(255, 255, 255, 255),
+ int width = -1, int height = -1);
+ void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
+ TransparentSurface *scale(int xSize, int ySize) const;
+private:
+ static int *scaleLine(int size, int srcSize);
+};
+
+/**
+ * A deleter for Surface objects which can be used with SharedPtr.
+ *
+ * This deleter assures Surface::free is called on deletion.
+ */
+/*struct SharedPtrTransparentSurfaceDeleter {
+ void operator()(TransparentSurface *ptr) {
+ ptr->free();
+ delete ptr;
+ }
+};*/
+
+
+} // End of namespace Graphics
+
+
+#endif