COMMON: Copy TransparentSurface from Wintermute engine to common code
This commit is contained in:
parent
215f5f9a49
commit
7322d905b3
7 changed files with 1387 additions and 0 deletions
|
@ -17,6 +17,9 @@ MODULE_OBJS := \
|
|||
scaler/thumbnail_intern.o \
|
||||
sjis.o \
|
||||
surface.o \
|
||||
transform_struct.o \
|
||||
transform_tools.o \
|
||||
transparent_surface.o \
|
||||
thumbnail.o \
|
||||
VectorRenderer.o \
|
||||
VectorRendererSpec.o \
|
||||
|
|
120
graphics/transform_struct.cpp
Normal file
120
graphics/transform_struct.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* 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/transform_struct.h"
|
||||
#include "graphics/transparent_surface.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
void TransformStruct::init(Common::Point zoom, uint32 angle, Common::Point hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Common::Point offset) {
|
||||
_zoom = zoom;
|
||||
_angle = angle;
|
||||
_hotspot = hotspot;
|
||||
_blendMode = blendMode;
|
||||
_rgbaMod = rgbaMod;
|
||||
_alphaDisable = alphaDisable;
|
||||
_flip = 0;
|
||||
_flip += FLIP_H * mirrorX;
|
||||
_flip += FLIP_V * mirrorY;
|
||||
_offset = offset;
|
||||
_numTimesX = 1;
|
||||
_numTimesY = 1;
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
|
||||
init(Common::Point(zoomX, zoomY),
|
||||
angle,
|
||||
Common::Point(hotspotX, hotspotY),
|
||||
false,
|
||||
blendMode,
|
||||
rgbaMod,
|
||||
mirrorX, mirrorY,
|
||||
Common::Point(offsetX, offsetY));
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) {
|
||||
init(Common::Point((int)(zoomX / 100.0 * kDefaultZoomX),
|
||||
(int)(zoomY / 100.0 * kDefaultZoomY)),
|
||||
angle,
|
||||
Common::Point(hotspotX, hotspotY),
|
||||
false,
|
||||
blendMode,
|
||||
rgbaMod,
|
||||
mirrorX, mirrorY,
|
||||
Common::Point(offsetX, offsetY));
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) {
|
||||
init(Common::Point(zoomX, zoomY),
|
||||
kDefaultAngle,
|
||||
Common::Point(kDefaultHotspotX, kDefaultHotspotY),
|
||||
false,
|
||||
blendMode,
|
||||
rgbaMod,
|
||||
mirrorX,
|
||||
mirrorY,
|
||||
Common::Point(kDefaultOffsetX, kDefaultOffsetY));
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) {
|
||||
init(Common::Point(zoomX, zoomY),
|
||||
angle,
|
||||
Common::Point(hotspotX, hotspotY),
|
||||
true,
|
||||
BLEND_NORMAL,
|
||||
kDefaultRgbaMod,
|
||||
false, false,
|
||||
Common::Point(kDefaultOffsetX, kDefaultOffsetY));
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) {
|
||||
init(Common::Point(kDefaultZoomX, kDefaultZoomY),
|
||||
kDefaultAngle,
|
||||
Common::Point(kDefaultHotspotX, kDefaultHotspotY),
|
||||
false,
|
||||
BLEND_NORMAL,
|
||||
kDefaultRgbaMod,
|
||||
false, false,
|
||||
Common::Point(kDefaultOffsetX, kDefaultOffsetY));
|
||||
_numTimesX = numTimesX;
|
||||
_numTimesY = numTimesY;
|
||||
}
|
||||
|
||||
TransformStruct::TransformStruct() {
|
||||
init(Common::Point(kDefaultZoomX, kDefaultZoomY),
|
||||
kDefaultAngle,
|
||||
Common::Point(kDefaultHotspotX, kDefaultHotspotY),
|
||||
true,
|
||||
BLEND_NORMAL,
|
||||
kDefaultRgbaMod,
|
||||
false, false,
|
||||
Common::Point(kDefaultOffsetX, kDefaultOffsetY));
|
||||
}
|
||||
|
||||
bool TransformStruct::getMirrorX() const {
|
||||
return (bool)(_flip & FLIP_H);
|
||||
}
|
||||
|
||||
bool TransformStruct::getMirrorY() const {
|
||||
return (bool)(_flip & FLIP_V);
|
||||
}
|
||||
} // End of namespace Graphics
|
97
graphics/transform_struct.h
Normal file
97
graphics/transform_struct.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/* 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_TRANSFORM_STRUCT_H
|
||||
#define GRAPHICS_TRANSFORM_STRUCT_H
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
enum TSpriteBlendMode {
|
||||
BLEND_UNKNOWN = -1,
|
||||
BLEND_NORMAL = 0,
|
||||
BLEND_ADDITIVE = 1,
|
||||
BLEND_SUBTRACTIVE = 2,
|
||||
NUM_BLEND_MODES
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains all the required information that define a transform.
|
||||
* Same source sprite + same TransformStruct = Same resulting sprite.
|
||||
* Has a number of overloaded constructors to accomodate various argument lists.
|
||||
*/
|
||||
|
||||
const int32 kDefaultZoomX = 100;
|
||||
const int32 kDefaultZoomY = 100;
|
||||
const uint32 kDefaultRgbaMod = 0xFFFFFFFF;
|
||||
const int32 kDefaultHotspotX = 0;
|
||||
const int32 kDefaultHotspotY = 0;
|
||||
const int32 kDefaultOffsetX = 0;
|
||||
const int32 kDefaultOffsetY = 0;
|
||||
const int32 kDefaultAngle = 0;
|
||||
|
||||
struct TransformStruct {
|
||||
private:
|
||||
void init(Common::Point zoom, uint32 angle, Common::Point hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Common::Point offset);
|
||||
|
||||
public:
|
||||
TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0);
|
||||
TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0);
|
||||
TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false);
|
||||
TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0);
|
||||
TransformStruct(int32 numTimesX, int32 numTimesY);
|
||||
TransformStruct();
|
||||
|
||||
Common::Point _zoom; ///< Zoom; 100 = no zoom
|
||||
Common::Point _hotspot; ///< Position of the hotspot
|
||||
int32 _angle; ///< Rotation angle, in degrees
|
||||
byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX
|
||||
bool _alphaDisable;
|
||||
TSpriteBlendMode _blendMode;
|
||||
uint32 _rgbaMod; ///< RGBa
|
||||
Common::Point _offset;
|
||||
int32 _numTimesX;
|
||||
int32 _numTimesY;
|
||||
|
||||
bool getMirrorX() const;
|
||||
bool getMirrorY() const;
|
||||
|
||||
bool operator==(const TransformStruct &compare) const {
|
||||
return (compare._angle == _angle &&
|
||||
compare._flip == _flip &&
|
||||
compare._zoom == _zoom &&
|
||||
compare._offset == _offset &&
|
||||
compare._alphaDisable == _alphaDisable &&
|
||||
compare._rgbaMod == _rgbaMod &&
|
||||
compare._blendMode == _blendMode &&
|
||||
compare._numTimesX == _numTimesX &&
|
||||
compare._numTimesY == _numTimesY
|
||||
);
|
||||
}
|
||||
|
||||
bool operator!=(const TransformStruct &compare) const {
|
||||
return !(compare == *this);
|
||||
}
|
||||
};
|
||||
} // End of namespace Graphics
|
||||
#endif
|
87
graphics/transform_tools.cpp
Normal file
87
graphics/transform_tools.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* 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/transform_tools.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
FloatPoint TransformTools::transformPoint(FloatPoint point, const float rotate, const Common::Point &zoom, const bool mirrorX, const bool mirrorY) {
|
||||
float rotateRad = rotate * M_PI / 180.0f;
|
||||
float x = point.x;
|
||||
float y = point.y;
|
||||
x = (x * zoom.x) / kDefaultZoomX;
|
||||
y = (y * zoom.y) / kDefaultZoomY;
|
||||
#if 0
|
||||
// TODO: Mirroring should be done before rotation, but the blitting
|
||||
// code does the inverse, so we match that for now.
|
||||
if (mirrorX)
|
||||
x *= -1;
|
||||
if (mirrorY)
|
||||
y *= -1;
|
||||
#endif
|
||||
FloatPoint newPoint;
|
||||
newPoint.x = x * cos(rotateRad) - y * sin(rotateRad);
|
||||
newPoint.y = x * sin(rotateRad) + y * cos(rotateRad);
|
||||
if (mirrorX) {
|
||||
newPoint.x *= -1;
|
||||
}
|
||||
if (mirrorY) {
|
||||
newPoint.y *= -1;
|
||||
}
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
Common::Rect TransformTools::newRect(const Common::Rect &oldRect, const TransformStruct &transform, Common::Point *newHotspot) {
|
||||
Common::Point nw(oldRect.left, oldRect.top);
|
||||
Common::Point ne(oldRect.right, oldRect.top);
|
||||
Common::Point sw(oldRect.left, oldRect.bottom);
|
||||
Common::Point se(oldRect.right, oldRect.bottom);
|
||||
|
||||
FloatPoint nw1, ne1, sw1, se1;
|
||||
|
||||
nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom);
|
||||
ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom);
|
||||
sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom);
|
||||
se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom);
|
||||
|
||||
float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y)));
|
||||
float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y)));
|
||||
float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x)));
|
||||
float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x)));
|
||||
|
||||
if (newHotspot) {
|
||||
newHotspot->y = (uint32)(-floor(top));
|
||||
newHotspot->x = (uint32)(-floor(left));
|
||||
}
|
||||
|
||||
Common::Rect res;
|
||||
res.top = (int32)(floor(top)) + transform._hotspot.y;
|
||||
res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y;
|
||||
res.left = (int32)(floor(left)) + transform._hotspot.x;
|
||||
res.right = (int32)(ceil(right)) + transform._hotspot.x;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
77
graphics/transform_tools.h
Normal file
77
graphics/transform_tools.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* 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_TRANSFORM_TOOLS_H
|
||||
#define GRAPHICS_TRANSFORM_TOOLS_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/transform_struct.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
static const float kEpsilon = 0.00001; // arbitrarily taken number
|
||||
|
||||
struct FloatPoint {
|
||||
float x;
|
||||
float y;
|
||||
FloatPoint() : x(0), y(0) {}
|
||||
FloatPoint(float x1, float y1) : x(x1), y(y1) {}
|
||||
FloatPoint(const Common::Point p) : x(p.x), y(p.y) {}
|
||||
bool operator==(const FloatPoint &p) const { return fabs(x - p.x) < kEpsilon && fabs(y - p.y) < kEpsilon; }
|
||||
bool operator!=(const FloatPoint &p) const { return fabs(x - p.x) > kEpsilon || fabs(y - p.y) > kEpsilon; }
|
||||
FloatPoint operator+(const FloatPoint &delta) const { return FloatPoint (x + delta.x, y + delta.y); }
|
||||
FloatPoint operator-(const FloatPoint &delta) const { return FloatPoint (x - delta.x, y - delta.y); }
|
||||
|
||||
FloatPoint& operator+=(const FloatPoint &delta) {
|
||||
x += delta.x;
|
||||
y += delta.y;
|
||||
return *this;
|
||||
}
|
||||
FloatPoint& operator-=(const FloatPoint &delta) {
|
||||
x -= delta.x;
|
||||
y -= delta.y;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class TransformTools {
|
||||
public:
|
||||
/**
|
||||
* Basic transform (scale + rotate) for a single point
|
||||
*/
|
||||
static FloatPoint transformPoint(FloatPoint point, const float rotate, const Common::Point &zoom, const bool mirrorX = false, const bool mirrorY = false);
|
||||
|
||||
/**
|
||||
* @param &point the point on which the transform is to be applied
|
||||
* @param rotate the angle in degrees
|
||||
* @param &zoom zoom x,y in percent
|
||||
* @param mirrorX flip along the vertical axis?
|
||||
* @param mirrorY flip along the horizontal axis?
|
||||
* @return the smallest rect that can contain the transformed sprite
|
||||
* and, as a side-effect, "newHotspot" will tell you where the hotspot will
|
||||
* have ended up in the new rect, for centering.
|
||||
*/
|
||||
static Common::Rect newRect(const Common::Rect &oldRect, const TransformStruct &transform, Common::Point *newHotspot);
|
||||
};
|
||||
|
||||
} // End of namespace Wintermute
|
||||
#endif
|
851
graphics/transparent_surface.cpp
Normal file
851
graphics/transparent_surface.cpp
Normal file
|
@ -0,0 +1,851 @@
|
|||
/* 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.
|
||||
*
|
||||
*
|
||||
* The bottom part of this is file is adapted from SDL_rotozoom.c. The
|
||||
* relevant copyright notice for those specific functions can be found at the
|
||||
* top of that section.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/util.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/math.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/primitives.h"
|
||||
#include "graphics/transparent_surface.h"
|
||||
#include "graphics/transform_tools.h"
|
||||
|
||||
//#define ENABLE_BILINEAR
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
static const int kAShift = 0;//img->format.aShift;
|
||||
|
||||
static const int kBModShift = 0;//img->format.bShift;
|
||||
static const int kGModShift = 8;//img->format.gShift;
|
||||
static const int kRModShift = 16;//img->format.rShift;
|
||||
static const int kAModShift = 24;//img->format.aShift;
|
||||
|
||||
#ifdef SCUMM_LITTLE_ENDIAN
|
||||
static const int kAIndex = 0;
|
||||
static const int kBIndex = 1;
|
||||
static const int kGIndex = 2;
|
||||
static const int kRIndex = 3;
|
||||
|
||||
#else
|
||||
static const int kAIndex = 3;
|
||||
static const int kBIndex = 2;
|
||||
static const int kGIndex = 1;
|
||||
static const int kRIndex = 0;
|
||||
#endif
|
||||
|
||||
void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
|
||||
void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
|
||||
void doBlitAlphaBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
|
||||
void doBlitAdditiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
|
||||
void doBlitSubtractiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
|
||||
|
||||
TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {}
|
||||
|
||||
TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _alphaMode(ALPHA_FULL) {
|
||||
if (copyData) {
|
||||
copyFrom(surf);
|
||||
} else {
|
||||
w = surf.w;
|
||||
h = surf.h;
|
||||
pitch = surf.pitch;
|
||||
format = surf.format;
|
||||
// We need to cast the const qualifier away here because 'pixels'
|
||||
// always needs to be writable. 'surf' however is a constant Surface,
|
||||
// thus getPixels will always return const pixel data.
|
||||
pixels = const_cast<void *>(surf.getPixels());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized version of doBlit to be used w/opaque blitting (no alpha).
|
||||
*/
|
||||
void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
|
||||
|
||||
byte *in;
|
||||
byte *out;
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
memcpy(out, in, width * 4);
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
out[kAIndex] = 0xFF;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized version of doBlit to be used w/binary blitting (blit or no-blit, no blending).
|
||||
*/
|
||||
void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
|
||||
|
||||
byte *in;
|
||||
byte *out;
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
uint32 pix = *(uint32 *)in;
|
||||
int a = (pix >> kAShift) & 0xff;
|
||||
|
||||
if (a != 0) { // Full opacity (Any value not exactly 0 is Opaque here)
|
||||
*(uint32 *)out = pix;
|
||||
out[kAIndex] = 0xFF;
|
||||
}
|
||||
out += 4;
|
||||
in += inStep;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized version of doBlit to be used with alpha blended blitting
|
||||
* @param ino a pointer to the input surface
|
||||
* @param outo a pointer to the output surface
|
||||
* @param width width of the input surface
|
||||
* @param height height of the input surface
|
||||
* @param pitch pitch of the output surface - that is, width in bytes of every row, usually bpp * width of the TARGET surface (the area we are blitting to might be smaller, do the math)
|
||||
* @inStep size in bytes to skip to address each pixel, usually bpp of the source surface
|
||||
* @inoStep width in bytes of every row on the *input* surface / kind of like pitch
|
||||
* @color colormod in 0xAARRGGBB format - 0xFFFFFFFF for no colormod
|
||||
*/
|
||||
void doBlitAlphaBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
|
||||
byte *in;
|
||||
byte *out;
|
||||
|
||||
if (color == 0xffffffff) {
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
if (in[kAIndex] != 0) {
|
||||
out[kAIndex] = 255;
|
||||
out[kRIndex] = ((in[kRIndex] * in[kAIndex]) + out[kRIndex] * (255 - in[kAIndex])) >> 8;
|
||||
out[kGIndex] = ((in[kGIndex] * in[kAIndex]) + out[kGIndex] * (255 - in[kAIndex])) >> 8;
|
||||
out[kBIndex] = ((in[kBIndex] * in[kAIndex]) + out[kBIndex] * (255 - in[kAIndex])) >> 8;
|
||||
}
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
} else {
|
||||
|
||||
byte ca = (color >> kAModShift) & 0xFF;
|
||||
byte cr = (color >> kRModShift) & 0xFF;
|
||||
byte cg = (color >> kGModShift) & 0xFF;
|
||||
byte cb = (color >> kBModShift) & 0xFF;
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
uint32 ina = in[kAIndex] * ca >> 8;
|
||||
out[kAIndex] = 255;
|
||||
out[kBIndex] = (out[kBIndex] * (255 - ina) >> 8);
|
||||
out[kGIndex] = (out[kGIndex] * (255 - ina) >> 8);
|
||||
out[kRIndex] = (out[kRIndex] * (255 - ina) >> 8);
|
||||
|
||||
out[kBIndex] = out[kBIndex] + (in[kBIndex] * ina * cb >> 16);
|
||||
out[kGIndex] = out[kGIndex] + (in[kGIndex] * ina * cg >> 16);
|
||||
out[kRIndex] = out[kRIndex] + (in[kRIndex] * ina * cr >> 16);
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized version of doBlit to be used with additive blended blitting
|
||||
*/
|
||||
void doBlitAdditiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
|
||||
byte *in;
|
||||
byte *out;
|
||||
|
||||
if (color == 0xffffffff) {
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
if (in[kAIndex] != 0) {
|
||||
out[kRIndex] = MIN((in[kRIndex] * in[kAIndex] >> 8) + out[kRIndex], 255);
|
||||
out[kGIndex] = MIN((in[kGIndex] * in[kAIndex] >> 8) + out[kGIndex], 255);
|
||||
out[kBIndex] = MIN((in[kBIndex] * in[kAIndex] >> 8) + out[kBIndex], 255);
|
||||
}
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
} else {
|
||||
|
||||
byte ca = (color >> kAModShift) & 0xFF;
|
||||
byte cr = (color >> kRModShift) & 0xFF;
|
||||
byte cg = (color >> kGModShift) & 0xFF;
|
||||
byte cb = (color >> kBModShift) & 0xFF;
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
uint32 ina = in[kAIndex] * ca >> 8;
|
||||
|
||||
if (cb != 255) {
|
||||
out[kBIndex] = MIN(out[kBIndex] + ((in[kBIndex] * cb * ina) >> 16), 255u);
|
||||
} else {
|
||||
out[kBIndex] = MIN(out[kBIndex] + (in[kBIndex] * ina >> 8), 255u);
|
||||
}
|
||||
|
||||
if (cg != 255) {
|
||||
out[kGIndex] = MIN(out[kGIndex] + ((in[kGIndex] * cg * ina) >> 16), 255u);
|
||||
} else {
|
||||
out[kGIndex] = MIN(out[kGIndex] + (in[kGIndex] * ina >> 8), 255u);
|
||||
}
|
||||
|
||||
if (cr != 255) {
|
||||
out[kRIndex] = MIN(out[kRIndex] + ((in[kRIndex] * cr * ina) >> 16), 255u);
|
||||
} else {
|
||||
out[kRIndex] = MIN(out[kRIndex] + (in[kRIndex] * ina >> 8), 255u);
|
||||
}
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized version of doBlit to be used with subtractive blended blitting
|
||||
*/
|
||||
void doBlitSubtractiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
|
||||
byte *in;
|
||||
byte *out;
|
||||
|
||||
if (color == 0xffffffff) {
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
if (in[kAIndex] != 0) {
|
||||
out[kRIndex] = MAX(out[kRIndex] - ((in[kRIndex] * out[kRIndex]) * in[kAIndex] >> 16), 0);
|
||||
out[kGIndex] = MAX(out[kGIndex] - ((in[kGIndex] * out[kGIndex]) * in[kAIndex] >> 16), 0);
|
||||
out[kBIndex] = MAX(out[kBIndex] - ((in[kBIndex] * out[kBIndex]) * in[kAIndex] >> 16), 0);
|
||||
}
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
} else {
|
||||
|
||||
byte cr = (color >> kRModShift) & 0xFF;
|
||||
byte cg = (color >> kGModShift) & 0xFF;
|
||||
byte cb = (color >> kBModShift) & 0xFF;
|
||||
|
||||
for (uint32 i = 0; i < height; i++) {
|
||||
out = outo;
|
||||
in = ino;
|
||||
for (uint32 j = 0; j < width; j++) {
|
||||
|
||||
out[kAIndex] = 255;
|
||||
if (cb != 255) {
|
||||
out[kBIndex] = MAX(out[kBIndex] - ((in[kBIndex] * cb * (out[kBIndex]) * in[kAIndex]) >> 24), 0);
|
||||
} else {
|
||||
out[kBIndex] = MAX(out[kBIndex] - (in[kBIndex] * (out[kBIndex]) * in[kAIndex] >> 16), 0);
|
||||
}
|
||||
|
||||
if (cg != 255) {
|
||||
out[kGIndex] = MAX(out[kGIndex] - ((in[kGIndex] * cg * (out[kGIndex]) * in[kAIndex]) >> 24), 0);
|
||||
} else {
|
||||
out[kGIndex] = MAX(out[kGIndex] - (in[kGIndex] * (out[kGIndex]) * in[kAIndex] >> 16), 0);
|
||||
}
|
||||
|
||||
if (cr != 255) {
|
||||
out[kRIndex] = MAX(out[kRIndex] - ((in[kRIndex] * cr * (out[kRIndex]) * in[kAIndex]) >> 24), 0);
|
||||
} else {
|
||||
out[kRIndex] = MAX(out[kRIndex] - (in[kRIndex] * (out[kRIndex]) * in[kAIndex] >> 16), 0);
|
||||
}
|
||||
|
||||
in += inStep;
|
||||
out += 4;
|
||||
}
|
||||
outo += pitch;
|
||||
ino += inoStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
|
||||
|
||||
Common::Rect retSize;
|
||||
retSize.top = 0;
|
||||
retSize.left = 0;
|
||||
retSize.setWidth(0);
|
||||
retSize.setHeight(0);
|
||||
// Check if we need to draw anything at all
|
||||
int ca = (color >> 24) & 0xff;
|
||||
|
||||
if (ca == 0) {
|
||||
return retSize;
|
||||
}
|
||||
|
||||
// Create an encapsulating surface for the data
|
||||
TransparentSurface srcImage(*this, false);
|
||||
// TODO: Is the data really in the screen format?
|
||||
if (format.bytesPerPixel != 4) {
|
||||
warning("TransparentSurface can only blit 32bpp images, but got %d", format.bytesPerPixel * 8);
|
||||
return retSize;
|
||||
}
|
||||
|
||||
if (pPartRect) {
|
||||
|
||||
int xOffset = pPartRect->left;
|
||||
int yOffset = pPartRect->top;
|
||||
|
||||
if (flipping & FLIP_V) {
|
||||
yOffset = srcImage.h - pPartRect->bottom;
|
||||
}
|
||||
|
||||
if (flipping & FLIP_H) {
|
||||
xOffset = srcImage.w - pPartRect->right;
|
||||
}
|
||||
|
||||
srcImage.pixels = getBasePtr(xOffset, yOffset);
|
||||
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 = nullptr;
|
||||
Graphics::Surface *imgScaled = nullptr;
|
||||
byte *savedPixels = nullptr;
|
||||
if ((width != srcImage.w) || (height != srcImage.h)) {
|
||||
// Scale the image
|
||||
img = imgScaled = srcImage.scale(width, height);
|
||||
savedPixels = (byte *)img->getPixels();
|
||||
} else {
|
||||
img = &srcImage;
|
||||
}
|
||||
|
||||
// Handle off-screen clipping
|
||||
if (posY < 0) {
|
||||
img->h = MAX(0, (int)img->h - -posY);
|
||||
img->setPixels((byte *)img->getBasePtr(0, -posY));
|
||||
posY = 0;
|
||||
}
|
||||
|
||||
if (posX < 0) {
|
||||
img->w = MAX(0, (int)img->w - -posX);
|
||||
img->setPixels((byte *)img->getBasePtr(-posX, 0));
|
||||
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 & FLIP_H) {
|
||||
inStep = -inStep;
|
||||
xp = img->w - 1;
|
||||
}
|
||||
|
||||
if (flipping & FLIP_V) {
|
||||
inoStep = -inoStep;
|
||||
yp = img->h - 1;
|
||||
}
|
||||
|
||||
byte *ino = (byte *)img->getBasePtr(xp, yp);
|
||||
byte *outo = (byte *)target.getBasePtr(posX, posY);
|
||||
|
||||
if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
|
||||
doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
|
||||
} else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
|
||||
doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
|
||||
} else {
|
||||
if (blendMode == BLEND_ADDITIVE) {
|
||||
doBlitAdditiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
|
||||
} else if (blendMode == BLEND_SUBTRACTIVE) {
|
||||
doBlitSubtractiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
|
||||
} else {
|
||||
assert(blendMode == BLEND_NORMAL);
|
||||
doBlitAlphaBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
retSize.setWidth(img->w);
|
||||
retSize.setHeight(img->h);
|
||||
|
||||
if (imgScaled) {
|
||||
imgScaled->setPixels(savedPixels);
|
||||
imgScaled->free();
|
||||
delete imgScaled;
|
||||
}
|
||||
|
||||
return retSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
assert(format.bytesPerPixel == 4);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlphaType TransparentSurface::getAlphaMode() const {
|
||||
return _alphaMode;
|
||||
}
|
||||
|
||||
void TransparentSurface::setAlphaMode(AlphaType mode) {
|
||||
_alphaMode = mode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The below two functions are adapted from SDL_rotozoom.c,
|
||||
taken from SDL_gfx-2.0.18.
|
||||
|
||||
Its copyright notice:
|
||||
|
||||
=============================================================================
|
||||
SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
|
||||
|
||||
Copyright (C) 2001-2012 Andreas Schiffler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
Andreas Schiffler -- aschiffler at ferzkopp dot net
|
||||
=============================================================================
|
||||
|
||||
|
||||
The functions have been adapted for different structures and coordinate
|
||||
systems.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
|
||||
|
||||
assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
|
||||
|
||||
Common::Point newHotspot;
|
||||
Common::Rect srcRect(0, 0, (int16)w, (int16)h);
|
||||
Common::Rect rect = TransformTools::newRect(Common::Rect(srcRect), transform, &newHotspot);
|
||||
Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top));
|
||||
|
||||
TransparentSurface *target = new TransparentSurface();
|
||||
assert(format.bytesPerPixel == 4);
|
||||
|
||||
int srcW = w;
|
||||
int srcH = h;
|
||||
int dstW = dstRect.width();
|
||||
int dstH = dstRect.height();
|
||||
|
||||
target->create((uint16)dstW, (uint16)dstH, this->format);
|
||||
|
||||
if (transform._zoom.x == 0 || transform._zoom.y == 0) {
|
||||
return target;
|
||||
}
|
||||
|
||||
uint32 invAngle = 360 - (transform._angle % 360);
|
||||
float invCos = cos(invAngle * M_PI / 180.0);
|
||||
float invSin = sin(invAngle * M_PI / 180.0);
|
||||
|
||||
struct tColorRGBA { byte r; byte g; byte b; byte a; };
|
||||
int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x));
|
||||
int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x));
|
||||
int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y));
|
||||
int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y));
|
||||
|
||||
|
||||
bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
|
||||
|
||||
int xd = (srcRect.left + transform._hotspot.x) << 16;
|
||||
int yd = (srcRect.top + transform._hotspot.y) << 16;
|
||||
int cx = newHotspot.x;
|
||||
int cy = newHotspot.y;
|
||||
|
||||
int ax = -icosx * cx;
|
||||
int ay = -isiny * cx;
|
||||
int sw = srcW - 1;
|
||||
int sh = srcH - 1;
|
||||
|
||||
tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0);
|
||||
|
||||
for (int y = 0; y < dstH; y++) {
|
||||
int t = cy - y;
|
||||
int sdx = ax + (isinx * t) + xd;
|
||||
int sdy = ay - (icosy * t) + yd;
|
||||
for (int x = 0; x < dstW; x++) {
|
||||
int dx = (sdx >> 16);
|
||||
int dy = (sdy >> 16);
|
||||
if (flipx) {
|
||||
dx = sw - dx;
|
||||
}
|
||||
if (flipy) {
|
||||
dy = sh - dy;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BILINEAR
|
||||
if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) {
|
||||
const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
|
||||
tColorRGBA c00, c01, c10, c11, cswap;
|
||||
c00 = *sp;
|
||||
sp += 1;
|
||||
c01 = *sp;
|
||||
sp += (this->pitch / 4);
|
||||
c11 = *sp;
|
||||
sp -= 1;
|
||||
c10 = *sp;
|
||||
if (flipx) {
|
||||
cswap = c00; c00=c01; c01=cswap;
|
||||
cswap = c10; c10=c11; c11=cswap;
|
||||
}
|
||||
if (flipy) {
|
||||
cswap = c00; c00=c10; c10=cswap;
|
||||
cswap = c01; c01=c11; c11=cswap;
|
||||
}
|
||||
/*
|
||||
* Interpolate colors
|
||||
*/
|
||||
int ex = (sdx & 0xffff);
|
||||
int ey = (sdy & 0xffff);
|
||||
int t1, t2;
|
||||
t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
|
||||
t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
|
||||
pc->r = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
|
||||
t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
|
||||
pc->g = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
|
||||
t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
|
||||
pc->b = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
|
||||
t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
|
||||
pc->a = (((t2 - t1) * ey) >> 16) + t1;
|
||||
}
|
||||
#else
|
||||
if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) {
|
||||
const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
|
||||
*pc = *sp;
|
||||
}
|
||||
#endif
|
||||
sdx += icosx;
|
||||
sdy += isiny;
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
|
||||
|
||||
Common::Rect srcRect(0, 0, (int16)w, (int16)h);
|
||||
Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight);
|
||||
|
||||
TransparentSurface *target = new TransparentSurface();
|
||||
|
||||
assert(format.bytesPerPixel == 4);
|
||||
|
||||
int srcW = srcRect.width();
|
||||
int srcH = srcRect.height();
|
||||
int dstW = dstRect.width();
|
||||
int dstH = dstRect.height();
|
||||
|
||||
target->create((uint16)dstW, (uint16)dstH, this->format);
|
||||
|
||||
#ifdef ENABLE_BILINEAR
|
||||
|
||||
// NB: The actual order of these bytes may not be correct, but
|
||||
// since all values are treated equal, that does not matter.
|
||||
struct tColorRGBA { byte r; byte g; byte b; byte a; };
|
||||
|
||||
bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
|
||||
|
||||
|
||||
int *sax = new int[dstW + 1];
|
||||
int *say = new int[dstH + 1];
|
||||
assert(sax && say);
|
||||
|
||||
/*
|
||||
* Precalculate row increments
|
||||
*/
|
||||
int spixelw = (srcW - 1);
|
||||
int spixelh = (srcH - 1);
|
||||
int sx = (int) (65536.0f * (float) spixelw / (float) (dstW - 1));
|
||||
int sy = (int) (65536.0f * (float) spixelh / (float) (dstH - 1));
|
||||
|
||||
/* Maximum scaled source size */
|
||||
int ssx = (srcW << 16) - 1;
|
||||
int ssy = (srcH << 16) - 1;
|
||||
|
||||
/* Precalculate horizontal row increments */
|
||||
int csx = 0;
|
||||
int *csax = sax;
|
||||
for (int x = 0; x <= dstW; x++) {
|
||||
*csax = csx;
|
||||
csax++;
|
||||
csx += sx;
|
||||
|
||||
/* Guard from overflows */
|
||||
if (csx > ssx) {
|
||||
csx = ssx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Precalculate vertical row increments */
|
||||
int csy = 0;
|
||||
int *csay = say;
|
||||
for (int y = 0; y <= dstH; y++) {
|
||||
*csay = csy;
|
||||
csay++;
|
||||
csy += sy;
|
||||
|
||||
/* Guard from overflows */
|
||||
if (csy > ssy) {
|
||||
csy = ssy;
|
||||
}
|
||||
}
|
||||
|
||||
const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0, 0);
|
||||
tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0, 0);
|
||||
int spixelgap = srcW;
|
||||
|
||||
if (flipx) {
|
||||
sp += spixelw;
|
||||
}
|
||||
if (flipy) {
|
||||
sp += spixelgap * spixelh;
|
||||
}
|
||||
|
||||
csay = say;
|
||||
for (int y = 0; y < dstH; y++) {
|
||||
const tColorRGBA *csp = sp;
|
||||
csax = sax;
|
||||
for (int x = 0; x < dstW; x++) {
|
||||
/*
|
||||
* Setup color source pointers
|
||||
*/
|
||||
int ex = (*csax & 0xffff);
|
||||
int ey = (*csay & 0xffff);
|
||||
int cx = (*csax >> 16);
|
||||
int cy = (*csay >> 16);
|
||||
|
||||
const tColorRGBA *c00, *c01, *c10, *c11;
|
||||
c00 = sp;
|
||||
c01 = sp;
|
||||
c10 = sp;
|
||||
if (cy < spixelh) {
|
||||
if (flipy) {
|
||||
c10 -= spixelgap;
|
||||
} else {
|
||||
c10 += spixelgap;
|
||||
}
|
||||
}
|
||||
c11 = c10;
|
||||
if (cx < spixelw) {
|
||||
if (flipx) {
|
||||
c01--;
|
||||
c11--;
|
||||
} else {
|
||||
c01++;
|
||||
c11++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw and interpolate colors
|
||||
*/
|
||||
int t1, t2;
|
||||
t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
|
||||
t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
|
||||
dp->r = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
|
||||
t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
|
||||
dp->g = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
|
||||
t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
|
||||
dp->b = (((t2 - t1) * ey) >> 16) + t1;
|
||||
t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
|
||||
t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
|
||||
dp->a = (((t2 - t1) * ey) >> 16) + t1;
|
||||
|
||||
/*
|
||||
* Advance source pointer x
|
||||
*/
|
||||
int *salastx = csax;
|
||||
csax++;
|
||||
int sstepx = (*csax >> 16) - (*salastx >> 16);
|
||||
if (flipx) {
|
||||
sp -= sstepx;
|
||||
} else {
|
||||
sp += sstepx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance destination pointer x
|
||||
*/
|
||||
dp++;
|
||||
}
|
||||
/*
|
||||
* Advance source pointer y
|
||||
*/
|
||||
int *salasty = csay;
|
||||
csay++;
|
||||
int sstepy = (*csay >> 16) - (*salasty >> 16);
|
||||
sstepy *= spixelgap;
|
||||
if (flipy) {
|
||||
sp = csp - sstepy;
|
||||
} else {
|
||||
sp = csp + sstepy;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] sax;
|
||||
delete[] say;
|
||||
|
||||
#else
|
||||
|
||||
int *scaleCacheX = new int[dstW];
|
||||
for (int x = 0; x < dstW; x++) {
|
||||
scaleCacheX[x] = (x * srcW) / dstW;
|
||||
}
|
||||
|
||||
for (int y = 0; y < dstH; y++) {
|
||||
uint32 *destP = (uint32 *)target->getBasePtr(0, y);
|
||||
const uint32 *srcP = (const uint32 *)getBasePtr(0, (y * srcH) / dstH);
|
||||
for (int x = 0; x < dstW; x++) {
|
||||
*destP++ = srcP[scaleCacheX[x]];
|
||||
}
|
||||
}
|
||||
delete[] scaleCacheX;
|
||||
|
||||
#endif
|
||||
|
||||
return target;
|
||||
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
152
graphics/transparent_surface.h
Normal file
152
graphics/transparent_surface.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* 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"
|
||||
#include "graphics/transform_struct.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 Graphics {
|
||||
|
||||
// Enums
|
||||
/**
|
||||
@brief The possible flipping parameters for the blit method.
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
enum AlphaType {
|
||||
ALPHA_OPAQUE = 0,
|
||||
ALPHA_BINARY = 1,
|
||||
ALPHA_FULL = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
@brief renders the surface to another surface
|
||||
@param target a pointer to the target surface. 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 pPartRect 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 height 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 = nullptr,
|
||||
uint color = BS_ARGB(255, 255, 255, 255),
|
||||
int width = -1, int height = -1,
|
||||
TSpriteBlendMode blend = BLEND_NORMAL);
|
||||
void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
|
||||
|
||||
/**
|
||||
* @brief Scale function; this returns a transformed version of this surface after rotation and
|
||||
* scaling. Please do not use this if angle != 0, use rotoscale.
|
||||
*
|
||||
* @param newWidth the resulting width.
|
||||
* @param newHeight the resulting height.
|
||||
* @see TransformStruct
|
||||
*/
|
||||
TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const;
|
||||
|
||||
/**
|
||||
* @brief Rotoscale function; this returns a transformed version of this surface after rotation and
|
||||
* scaling. Please do not use this if angle == 0, use plain old scaling function.
|
||||
*
|
||||
* @param transform a TransformStruct wrapping the required info. @see TransformStruct
|
||||
*
|
||||
*/
|
||||
TransparentSurface *rotoscale(const TransformStruct &transform) const;
|
||||
AlphaType getAlphaMode() const;
|
||||
void setAlphaMode(AlphaType);
|
||||
private:
|
||||
AlphaType _alphaMode;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
Loading…
Add table
Add a link
Reference in a new issue