WINTERMUTE: Add transparentSurface internally for now, to allow alpha-blended blits.

This commit is contained in:
Einar Johan Trøan Sømåen
2012-06-02 13:05:42 +02:00
parent a53fa953a4
commit ae48c3f7e1
5 changed files with 493 additions and 42 deletions
+3 -12
View File
@@ -36,6 +36,7 @@
#include "engines/wintermute/BGame.h"
#include "engines/wintermute/BSprite.h"
#include "common/system.h"
#include "engines/wintermute/graphics/transparentSurface.h"
namespace WinterMute {
@@ -273,18 +274,8 @@ HRESULT CBRenderSDL::FadeToColor(uint32 Color, RECT *rect) {
// Replacement for SDL2's SDL_RenderCopy
void CBRenderSDL::drawFromSurface(Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect) {
for (int i = 0; i < srcRect->height(); i++) {
byte *destPtr = (byte*)_renderSurface->getBasePtr(dstRect->left, dstRect->top + i);
byte *srcPtr = (byte*)surf->getBasePtr(srcRect->left, srcRect->top + i);
for (int j = 0; j < srcRect->width(); j++) {
// TODO: Replace this with something less ugly, and more portable.
if (((byte *)srcPtr)[0] == 255) {
memcpy(destPtr, srcPtr, _renderSurface->format.bytesPerPixel);
}
srcPtr += _renderSurface->format.bytesPerPixel;
destPtr += _renderSurface->format.bytesPerPixel;
}
}
TransparentSurface src(*surf, false);
src.blit(*_renderSurface, dstRect->left, dstRect->top, TransparentSurface::FLIP_NONE, srcRect,BS_ARGB(255, 255, 255, 255), dstRect->width(), dstRect->height() );
}
//////////////////////////////////////////////////////////////////////////
HRESULT CBRenderSDL::DrawLine(int X1, int Y1, int X2, int Y2, uint32 Color) {
+43 -30
View File
@@ -36,9 +36,11 @@
#include "graphics/decoders/bmp.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
#include "engines/wintermute/graphics/transparentSurface.h"
#include "common/stream.h"
#include "BFileManager.h"
#include "PlatformSDL.h"
#include "common/system.h"
namespace WinterMute {
@@ -130,9 +132,12 @@ HRESULT CBSurfaceSDL::Create(const char *Filename, bool default_ck, byte ck_red,
// no alpha, set color key
/* if (surface->format.bytesPerPixel != 4)
SDL_SetColorKey(surf, SDL_TRUE, SDL_MapRGB(surf->format, ck_red, ck_green, ck_blue));*/
_surface = new Graphics::Surface();
_surface->copyFrom(*surface);
if (surface->format.bytesPerPixel == 4 && surface->format != g_system->getScreenFormat()) {
_surface = surface->convertTo(g_system->getScreenFormat());
} else {
_surface = new Graphics::Surface();
_surface->copyFrom(*surface);
}
//SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); //TODO
//_texture = SdlUtil::CreateTextureFromSurface(renderer->GetSdlRenderer(), surf);
@@ -184,16 +189,16 @@ HRESULT CBSurfaceSDL::Create(const char *Filename, bool default_ck, byte ck_red,
void CBSurfaceSDL::GenAlphaMask(Graphics::Surface *surface) {
warning("CBSurfaceSDL::GenAlphaMask - Not ported yet");
return;
#if 0
delete[] _alphaMask;
_alphaMask = NULL;
if (!surface) return;
#if 0
SDL_LockSurface(surface);
#endif
bool hasColorKey;
Uint32 colorKey;
Uint8 ckRed, ckGreen, ckBlue;
uint32 colorKey;
uint8 ckRed, ckGreen, ckBlue;
/* if (SDL_GetColorKey(surface, &colorKey) == 0) {
hasColorKey = true;
SDL_GetRGB(colorKey, surface->format, &ckRed, &ckGreen, &ckBlue);
@@ -204,10 +209,11 @@ void CBSurfaceSDL::GenAlphaMask(Graphics::Surface *surface) {
bool hasTransparency = false;
for (int y = 0; y < surface->h; y++) {
for (int x = 0; x < surface->w; x++) {
Uint32 pixel = GetPixel(surface, x, y);
uint32 pixel = GetPixel(surface, x, y);
Uint8 r, g, b, a;
SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a);
uint8 r, g, b, a;
surface->format.colorToARGB(pixel, a, r, g, b);
//SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a);
if (hasColorKey && r == ckRed && g == ckGreen && b == ckBlue)
a = 0;
@@ -216,23 +222,21 @@ void CBSurfaceSDL::GenAlphaMask(Graphics::Surface *surface) {
if (a < 255) hasTransparency = true;
}
}
#if 0
SDL_UnlockSurface(surface);
#endif
if (!hasTransparency) {
delete[] _alphaMask;
_alphaMask = NULL;
}
#endif
}
//////////////////////////////////////////////////////////////////////////
uint32 CBSurfaceSDL::GetPixel(Graphics::Surface *surface, int x, int y) {
warning("CBSurfaceSDL::GetPixel - Not ported yet");
#if 0
int bpp = surface->format->BytesPerPixel;
int bpp = surface->format.bytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
uint8 *p = (uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch (bpp) {
case 1:
@@ -240,24 +244,26 @@ uint32 CBSurfaceSDL::GetPixel(Graphics::Surface *surface, int x, int y) {
break;
case 2:
return *(Uint16 *)p;
return *(uint16 *)p;
break;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#ifdef SCUMM_BIG_ENDIAN
// if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
#else
//else
return p[0] | p[1] << 8 | p[2] << 16;
#endif
break;
case 4:
return *(Uint32 *)p;
return *(uint32 *)p;
break;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
#endif
return 0;
}
@@ -267,14 +273,14 @@ HRESULT CBSurfaceSDL::Create(int Width, int Height) {
#if 0
CBRenderSDL *renderer = static_cast<CBRenderSDL *>(Game->_renderer);
_texture = SDL_CreateTexture(renderer->GetSdlRenderer(), SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Width, Height);
#endif
_width = Width;
_height = Height;
#if 0
Game->AddMem(_width * _height * 4);
_valid = true;
#endif
_valid = true;
return S_OK;
}
@@ -284,14 +290,21 @@ HRESULT CBSurfaceSDL::CreateFromSDLSurface(Graphics::Surface *surface) {
#if 0
CBRenderSDL *renderer = static_cast<CBRenderSDL *>(Game->_renderer);
_texture = SDL_CreateTextureFromSurface(renderer->GetSdlRenderer(), surface);
#endif
if (_surface) {
_surface->free();
delete _surface;
_surface = NULL;
}
_surface = new Graphics::Surface();
_surface->copyFrom(*surface);
_width = surface->w;
_height = surface->h;
#if 0
Game->AddMem(_width * _height * 4);
_valid = true;
#endif
_valid = true;
return S_OK;
}
@@ -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
@@ -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
+1
View File
@@ -13,6 +13,7 @@ MODULE_OBJS := \
scriptables/SXMemBuffer.o \
scriptables/SXStore.o \
scriptables/SXString.o \
graphics/transparentSurface.o \
AdActor.o \
AdActorDir.o \
AdEntity.o \