scummvm/graphics/VectorRendererSpec.cpp
Bastien Bouclet 1d764bd787 GRAPHICS: Vector renderer clipping rect related cleanups
Selecting whether a clipping variant of a draw call needs to be used is
no longer the responsibility to the caller. The clipping rect is now
part of the state of the renderer.

Also fix some of the draw calls to better apply the clipping rect.
2019-10-07 21:47:42 +02:00

3843 lines
118 KiB
C++

/* 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/util.h"
#include "common/system.h"
#include "common/frac.h"
#include "graphics/surface.h"
#include "graphics/transparent_surface.h"
#include "graphics/nine_patch.h"
#include "graphics/colormasks.h"
#include "gui/ThemeEngine.h"
#include "graphics/VectorRenderer.h"
#include "graphics/VectorRendererSpec.h"
#define VECTOR_RENDERER_FAST_TRIANGLES
/** Fixed point SQUARE ROOT **/
inline frac_t fp_sqroot(uint32 x) {
#if 0
// Use the FPU to compute the square root and then convert it to fixed
// point data. On systems with a fast FPU, this can be a lot faster than
// the integer based code below - on my system roughly 50x! However, on
// systems without an FPU, the converse might be true.
// For now, we only use the integer based code.
return doubleToFrac(sqrt((double)x));
#else
// The code below wants to use a lot of registers, which is not good on
// x86 processors. By taking advantage of the fact the the input value is
// an integer, it might be possible to improve this. Furthermore, we could
// take advantage of the fact that we call this function several times on
// decreasing values. By feeding it the sqrt of the previous old x, as well
// as the old x, it should be possible to compute the correct sqrt with far
// fewer than 23 iterations.
uint32 root, remHI, remLO, testDIV, count;
root = 0;
remHI = 0;
remLO = x << 16;
count = 23;
do {
remHI = (remHI << 2) | (remLO >> 30);
remLO <<= 2;
root <<= 1;
testDIV = (root << 1) + 1;
if (remHI >= testDIV) {
remHI -= testDIV;
root++;
}
} while (count--);
return root;
#endif
}
/*
HELPER MACROS for Bresenham's circle drawing algorithm
Note the proper spelling on this header.
*/
#define BE_ALGORITHM() do { \
if (f >= 0) { \
y--; \
ddF_y += 2; \
f += ddF_y; \
py -= pitch; \
} \
px += pitch; \
ddF_x += 2; \
f += ddF_x + 1; \
} while(0)
#define BE_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color; \
*(ptr1 + (x) - (py)) = color; \
*(ptr2 - (x) - (py)) = color; \
*(ptr2 - (y) - (px)) = color; \
} while (0)
#define BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py) do { \
*(ptr3 - (y) + (px)) = color; \
*(ptr3 - (x) + (py)) = color; \
*(ptr4 + (x) + (py)) = color; \
*(ptr4 + (y) + (px)) = color; \
} while (0)
#define BE_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
BE_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py); \
BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
#define BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
*(ptr1 + (y) - (px)) = color; \
if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
*(ptr1 + (x) - (py)) = color; \
if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
*(ptr2 - (x) - (py)) = color; \
if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
*(ptr2 - (y) - (px)) = color; \
} while (0)
#define BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
*(ptr3 - (y) + (px)) = color; \
if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
*(ptr3 - (x) + (py)) = color; \
if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
*(ptr4 + (x) + (py)) = color; \
if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
*(ptr4 + (y) + (px)) = color; \
} while (0)
#define BE_DRAWCIRCLE_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color1; \
*(ptr2 - (x) - (py)) = color1; \
*(ptr2 - (y) - (px)) = color1; \
*(ptr3 - (y) + (px)) = color1; \
*(ptr3 - (x) + (py)) = color1; \
*(ptr4 + (x) + (py)) = color2; \
*(ptr4 + (y) + (px)) = color2; \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
*(ptr1 + (y) - (px)) = color1; \
if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
*(ptr1 + (x) - (py)) = color1; \
if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
*(ptr2 - (x) - (py)) = color1; \
if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
*(ptr2 - (y) - (px)) = color1; \
if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
*(ptr3 - (y) + (px)) = color1; \
if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
*(ptr3 - (x) + (py)) = color1; \
if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
*(ptr4 + (x) + (py)) = color2; \
if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
*(ptr4 + (y) + (px)) = color2; \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) - (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) - (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) + (y), (realY) - (x))) \
this->blendPixelPtr(ptr + (y) - (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) + (x), (realY) - (y))) \
this->blendPixelPtr(ptr + (x) - (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) - (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) - (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) - (x), (realY) - (y))) \
this->blendPixelPtr(ptr - (x) - (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) - (y), (realY) - (x))) \
this->blendPixelPtr(ptr - (y) - (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) + (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) + (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) - (y), (realY) + (x))) \
this->blendPixelPtr(ptr - (y) + (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) - (x), (realY) + (y))) \
this->blendPixelPtr(ptr - (x) + (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) + (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) + (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) + (x), (realY) + (y))) \
this->blendPixelPtr(ptr + (x) + (py), color, a); \
} while (0)
#define BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
if (IS_IN_CLIP((realX) + (y), (realY) + (x))) \
this->blendPixelPtr(ptr + (y) + (px), color, a); \
} while (0)
#define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color2; \
*(ptr2 - (x) - (py)) = color2; \
*(ptr2 - (y) - (px)) = color1; \
} while (0)
#define BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py) do { \
*(ptr3 - (y) + (px)) = color3; \
*(ptr3 - (x) + (py)) = color4; \
*(ptr4 + (x) + (py)) = color4; \
*(ptr4 + (y) + (px)) = color3; \
} while (0)
#define BE_DRAWCIRCLE_XCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py); \
BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
#define IS_IN_CLIP(x,y) (_clippingArea.left <= (x) && (x) < _clippingArea.right \
&& _clippingArea.top <= (y) && (y) < _clippingArea.bottom)
#define BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
*(ptr1 + (y) - (px)) = color1; \
\
if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
*(ptr1 + (x) - (py)) = color2; \
\
if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
*(ptr2 - (x) - (py)) = color2; \
\
if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
*(ptr2 - (y) - (px)) = color1; \
} while (0)
#define BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
*(ptr3 - (y) + (px)) = color3; \
\
if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
*(ptr3 - (x) + (py)) = color4; \
\
if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
*(ptr4 + (x) + (py)) = color4; \
\
if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
*(ptr4 + (y) + (px)) = color3; \
} while (0)
#define BE_DRAWCIRCLE_XCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
} while (0)
#define BE_RESET() do { \
f = 1 - r; \
ddF_x = 0; ddF_y = -2 * r; \
x = 0; y = r; px = 0; py = pitch * r; \
} while (0)
#define TRIANGLE_MAINX() \
if (error_term >= 0) { \
ptr_right += pitch; \
ptr_left += pitch; \
error_term += dysub; \
} else { \
error_term += ddy; \
} \
ptr_right++; \
ptr_left--;
#define TRIANGLE_MAINY() \
if (error_term >= 0) { \
ptr_right++; \
ptr_left--; \
error_term += dxsub; \
} else { \
error_term += ddx; \
} \
ptr_right += pitch; \
ptr_left += pitch;
/** HELPER MACROS for WU's circle drawing algorithm **/
#define WU_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py,a) do { \
this->blendPixelPtr(ptr1 + (y) - (px), color, a); \
this->blendPixelPtr(ptr1 + (x) - (py), color, a); \
this->blendPixelPtr(ptr2 - (x) - (py), color, a); \
this->blendPixelPtr(ptr2 - (y) - (px), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py,a) do { \
this->blendPixelPtr(ptr3 - (y) + (px), color, a); \
this->blendPixelPtr(ptr3 - (x) + (py), color, a); \
this->blendPixelPtr(ptr4 + (x) + (py), color, a); \
this->blendPixelPtr(ptr4 + (y) + (px), color, a); \
} while (0)
#define WU_DRAWCIRCLE(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) do { \
WU_DRAWCIRCLE_TOP(ptr1,ptr2,x,y,px,py,a); \
WU_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py,a); \
} while (0)
// Color depending on y
// Note: this is only for the outer pixels
#define WU_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py,a,func) do { \
this->func(ptr1 + (y) - (px), color1, a); \
this->func(ptr1 + (x) - (py), color2, a); \
this->func(ptr2 - (x) - (py), color2, a); \
this->func(ptr2 - (y) - (px), color1, a); \
} while (0)
#define WU_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py,a,func) do { \
this->func(ptr3 - (y) + (px), color3, a); \
this->func(ptr3 - (x) + (py), color4, a); \
this->func(ptr4 + (x) + (py), color4, a); \
this->func(ptr4 + (y) + (px), color3, a); \
} while (0)
#define WU_DRAWCIRCLE_XCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a,func) do { \
WU_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py,a,func); \
WU_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py,a,func); \
} while (0)
// Color depending on corner (tl,tr,bl: color1, br: color2)
// Note: this is only for the outer pixels
#define WU_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py,a) do { \
this->blendPixelPtr(ptr1 + (y) - (px), color1, a); \
this->blendPixelPtr(ptr1 + (x) - (py), color1, a); \
this->blendPixelPtr(ptr2 - (x) - (py), color1, a); \
this->blendPixelPtr(ptr2 - (y) - (px), color1, a); \
this->blendPixelPtr(ptr3 - (y) + (px), color1, a); \
this->blendPixelPtr(ptr3 - (x) + (py), color1, a); \
this->blendPixelPtr(ptr4 + (x) + (py), color2, a); \
this->blendPixelPtr(ptr4 + (y) + (px), color2, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) - (px), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) - (py), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) - (py), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) - (px), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) + (px), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) + (py), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) + (py), color, a); \
} while (0)
#define WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) + (px), color, a); \
} while (0)
// optimized Wu's algorithm
#define WU_ALGORITHM() do { \
oldT = T; \
T = fp_sqroot(rsq - y*y) ^ 0xFFFF; \
py += pitch; \
if (T < oldT) { \
x--; px -= pitch; \
} \
a2 = (T >> 8); \
a1 = ~a2; \
} while (0)
namespace Graphics {
/**
* Fills several pixels in a row with a given color.
*
* This is a replacement function for Common::fill, using an unrolled
* loop to maximize performance on most architectures.
* This function may (and should) be overloaded in any child renderers
* for portable platforms with platform-specific assembly code.
*
* This fill operation is extensively used throughout the renderer, so this
* counts as one of the main bottlenecks. Please replace it with assembly
* when possible!
*
* @param first Pointer to the first pixel to fill.
* @param last Pointer to the last pixel to fill.
* @param color Color of the pixel
*/
template<typename PixelType>
void colorFill(PixelType *first, PixelType *last, PixelType color) {
int count = (last - first);
if (!count)
return;
int n = (count + 7) >> 3;
switch (count % 8) {
case 0: do {
*first++ = color; // fall through
case 7: *first++ = color; // fall through
case 6: *first++ = color; // fall through
case 5: *first++ = color; // fall through
case 4: *first++ = color; // fall through
case 3: *first++ = color; // fall through
case 2: *first++ = color; // fall through
case 1: *first++ = color;
} while (--n > 0);
}
}
template<typename PixelType>
void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
if (realY < clippingArea.top || realY >= clippingArea.bottom)
return;
int count = (last - first);
if (realX > clippingArea.right || realX + count < clippingArea.left)
return;
if (realX < clippingArea.left) {
int diff = (clippingArea.left - realX);
realX += diff;
first += diff;
count -= diff;
}
if (clippingArea.right <= realX + count) {
int diff = (realX + count - clippingArea.right);
count -= diff;
}
if (!count)
return;
int n = (count + 7) >> 3;
switch (count % 8) {
case 0: do {
*first++ = color; // fall through
case 7: *first++ = color; // fall through
case 6: *first++ = color; // fall through
case 5: *first++ = color; // fall through
case 4: *first++ = color; // fall through
case 3: *first++ = color; // fall through
case 2: *first++ = color; // fall through
case 1: *first++ = color;
} while (--n > 0);
}
}
VectorRenderer *createRenderer(int mode) {
#ifdef DISABLE_FANCY_THEMES
assert(mode == GUI::ThemeEngine::kGfxStandard);
#endif
PixelFormat format = g_system->getOverlayFormat();
switch (mode) {
case GUI::ThemeEngine::kGfxStandard:
if (g_system->getOverlayFormat().bytesPerPixel == 4)
return new VectorRendererSpec<uint32>(format);
else if (g_system->getOverlayFormat().bytesPerPixel == 2)
return new VectorRendererSpec<uint16>(format);
break;
#ifndef DISABLE_FANCY_THEMES
case GUI::ThemeEngine::kGfxAntialias:
if (g_system->getOverlayFormat().bytesPerPixel == 4)
return new VectorRendererAA<uint32>(format);
else if (g_system->getOverlayFormat().bytesPerPixel == 2)
return new VectorRendererAA<uint16>(format);
break;
#endif
default:
break;
}
return 0;
}
template<typename PixelType>
VectorRendererSpec<PixelType>::
VectorRendererSpec(PixelFormat format) :
_format(format),
_redMask((0xFF >> format.rLoss) << format.rShift),
_greenMask((0xFF >> format.gLoss) << format.gShift),
_blueMask((0xFF >> format.bLoss) << format.bShift),
_alphaMask((0xFF >> format.aLoss) << format.aShift) {
_bitmapAlphaColor = _format.RGBToColor(255, 0, 255);
_clippingArea = Common::Rect(0, 0, 32767, 32767);
}
/****************************
* Gradient-related methods *
****************************/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
setGradientColors(uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2) {
_gradientEnd = _format.RGBToColor(r2, g2, b2);
_gradientStart = _format.RGBToColor(r1, g1, b1);
if (sizeof(PixelType) == 4) {
_gradientBytes[0] = ((_gradientEnd & _redMask) >> _format.rShift) - ((_gradientStart & _redMask) >> _format.rShift);
_gradientBytes[1] = ((_gradientEnd & _greenMask) >> _format.gShift) - ((_gradientStart & _greenMask) >> _format.gShift);
_gradientBytes[2] = ((_gradientEnd & _blueMask) >> _format.bShift) - ((_gradientStart & _blueMask) >> _format.bShift);
} else {
_gradientBytes[0] = (_gradientEnd & _redMask) - (_gradientStart & _redMask);
_gradientBytes[1] = (_gradientEnd & _greenMask) - (_gradientStart & _greenMask);
_gradientBytes[2] = (_gradientEnd & _blueMask) - (_gradientStart & _blueMask);
}
}
template<typename PixelType>
inline PixelType VectorRendererSpec<PixelType>::
calcGradient(uint32 pos, uint32 max) {
PixelType output = 0;
pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max;
if (sizeof(PixelType) == 4) {
output |= ((_gradientStart & _redMask) + (((_gradientBytes[0] * pos) >> 12) << _format.rShift)) & _redMask;
output |= ((_gradientStart & _greenMask) + (((_gradientBytes[1] * pos) >> 12) << _format.gShift)) & _greenMask;
output |= ((_gradientStart & _blueMask) + (((_gradientBytes[2] * pos) >> 12) << _format.bShift)) & _blueMask;
} else {
output |= ((_gradientStart & _redMask) + ((_gradientBytes[0] * pos) >> 12)) & _redMask;
output |= ((_gradientStart & _greenMask) + ((_gradientBytes[1] * pos) >> 12)) & _greenMask;
output |= ((_gradientStart & _blueMask) + ((_gradientBytes[2] * pos) >> 12)) & _blueMask;
}
output |= _alphaMask;
return output;
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
precalcGradient(int h) {
PixelType prevcolor = 0, color;
_gradCache.resize(0);
_gradIndexes.resize(0);
for (int i = 0; i < h + 2; i++) {
color = calcGradient(i, h);
if (color != prevcolor || i == 0 || i > h - 1) {
prevcolor = color;
_gradCache.push_back(color);
_gradIndexes.push_back(i);
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
gradientFill(PixelType *ptr, int width, int x, int y) {
bool ox = ((y & 1) == 1);
int curGrad = 0;
while (_gradIndexes[curGrad + 1] <= y)
curGrad++;
// precalcGradient assures that _gradIndexes entries always differ in
// their value. This assures stripSize is always different from zero.
int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
// Dithering:
// +--+ +--+ +--+ +--+
// | | | | | *| | *|
// | | | *| |* | |**|
// +--+ +--+ +--+ +--+
// 0 1 2 3
if (grad == 0 ||
_gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
stripSize < 2) { // the stip is small
colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
} else if (grad == 3 && ox) {
colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]);
} else {
for (int j = x; j < x + width; j++, ptr++) {
bool oy = ((j & 1) == 1);
if ((ox && oy) ||
((grad == 2 || grad == 3) && ox && !oy) ||
(grad == 3 && oy))
*ptr = _gradCache[curGrad + 1];
else
*ptr = _gradCache[curGrad];
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
gradientFillClip(PixelType *ptr, int width, int x, int y, int realX, int realY) {
if (realY < _clippingArea.top || realY >= _clippingArea.bottom) return;
bool ox = ((y & 1) == 1);
int curGrad = 0;
while (_gradIndexes[curGrad + 1] <= y)
curGrad++;
// precalcGradient assures that _gradIndexes entries always differ in
// their value. This assures stripSize is always different from zero.
int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
// Dithering:
// +--+ +--+ +--+ +--+
// | | | | | *| | *|
// | | | *| |* | |**|
// +--+ +--+ +--+ +--+
// 0 1 2 3
if (grad == 0 ||
_gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
stripSize < 2) { // the stip is small
colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
} else if (grad == 3 && ox) {
colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]);
} else {
for (int j = x; j < x + width; j++, ptr++) {
if (realX + j - x < _clippingArea.left || realX + j - x >= _clippingArea.right) continue;
bool oy = ((j & 1) == 1);
if ((ox && oy) ||
((grad == 2 || grad == 3) && ox && !oy) ||
(grad == 3 && oy))
*ptr = _gradCache[curGrad + 1];
else
*ptr = _gradCache[curGrad];
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
fillSurface() {
Common::Rect drawRect(0, 0, _activeSurface->w, _activeSurface->h);
drawRect.clip(_clippingArea);
if (drawRect.isEmpty()) {
return;
}
int h = _activeSurface->h;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, drawRect.top);
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillForeground) {
PixelType color = (Base::_fillMode == kFillBackground ? _bgColor : _fgColor);
PixelType *ptrLeft = (ptr + drawRect.left), *ptrRight = ptr + drawRect.right;
for (int i = drawRect.top; i < drawRect.bottom; i++) {
colorFill<PixelType>(ptrLeft, ptrRight, color);
ptrLeft += pitch;
ptrRight += pitch;
}
} else if (Base::_fillMode == kFillGradient) {
precalcGradient(h);
for (int i = drawRect.top; i < drawRect.bottom; i++) {
gradientFill(ptr + drawRect.left, drawRect.width(), 0, i);
ptr += pitch;
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
copyFrame(OSystem *sys, const Common::Rect &r) {
sys->copyRectToOverlay(
_activeSurface->getBasePtr(r.left, r.top),
_activeSurface->pitch,
r.left, r.top, r.width(), r.height()
);
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
blitSurface(const Graphics::Surface *source, const Common::Rect &r) {
assert(source->w == _activeSurface->w && source->h == _activeSurface->h);
byte *dst_ptr = (byte *)_activeSurface->getBasePtr(r.left, r.top);
const byte *src_ptr = (const byte *)source->getBasePtr(r.left, r.top);
const int dst_pitch = _activeSurface->pitch;
const int src_pitch = source->pitch;
int h = r.height();
const int w = r.width() * sizeof(PixelType);
while (h--) {
memcpy(dst_ptr, src_ptr, w);
dst_ptr += dst_pitch;
src_ptr += src_pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
blitSubSurface(const Graphics::Surface *source, const Common::Point &p) {
Common::Rect drawRect(p.x, p.y, p.x + source->w, p.y + source->h);
drawRect.clip(_clippingArea);
if (drawRect.isEmpty()) {
return;
}
int sourceOffsetX = drawRect.left - p.x;
int sourceOffsetY = drawRect.top - p.y;
byte *dst_ptr = (byte *)_activeSurface->getBasePtr(drawRect.left, drawRect.top);
const byte *src_ptr = (const byte *)source->getBasePtr(sourceOffsetX, sourceOffsetY);
const int dst_pitch = _activeSurface->pitch;
const int src_pitch = source->pitch;
int lines = drawRect.height();
const int sz = drawRect.width() * sizeof(PixelType);
while (lines--) {
memcpy(dst_ptr, src_ptr, sz);
dst_ptr += dst_pitch;
src_ptr += src_pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
blitKeyBitmap(const Graphics::Surface *source, const Common::Point &p) {
Common::Rect drawRect(p.x, p.y, p.x + source->w, p.y + source->h);
drawRect.clip(_clippingArea);
if (drawRect.isEmpty()) {
return;
}
int sourceOffsetX = drawRect.left - p.x;
int sourceOffsetY = drawRect.top - p.y;
PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(drawRect.left, drawRect.top);
const PixelType *src_ptr = (const PixelType *)source->getBasePtr(sourceOffsetX, sourceOffsetY);
int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int src_pitch = source->pitch / source->format.bytesPerPixel;
int w, h = drawRect.height();
while (h--) {
w = drawRect.width();
while (w--) {
if (*src_ptr != _bitmapAlphaColor)
*dst_ptr = *src_ptr;
dst_ptr++;
src_ptr++;
}
dst_ptr = dst_ptr - drawRect.width() + dst_pitch;
src_ptr = src_ptr - drawRect.width() + src_pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
blitAlphaBitmap(Graphics::TransparentSurface *source, const Common::Rect &r, GUI::ThemeEngine::AutoScaleMode autoscale,
Graphics::DrawStep::VectorAlignment xAlign, Graphics::DrawStep::VectorAlignment yAlign, int alpha) {
if (autoscale == GUI::ThemeEngine::kAutoScaleStretch) {
source->blit(*_activeSurface, r.left, r.top, Graphics::FLIP_NONE,
nullptr, TS_ARGB(alpha, 255, 255, 255),
r.width(), r.height());
} else if (autoscale == GUI::ThemeEngine::kAutoScaleFit) {
double ratio = (double)r.width() / source->w;
double ratio2 = (double)r.height() / source->h;
if (ratio2 < ratio)
ratio = ratio2;
int offx = 0, offy = 0;
if (xAlign == Graphics::DrawStep::kVectorAlignCenter)
offx = (r.width() - (int)(source->w * ratio)) >> 1;
if (yAlign == Graphics::DrawStep::kVectorAlignCenter)
offy = (r.height() - (int)(source->h * ratio)) >> 1;
source->blit(*_activeSurface, r.left + offx, r.top + offy, Graphics::FLIP_NONE,
nullptr, TS_ARGB(alpha, 255, 255, 255),
(int)(source->w * ratio), (int)(source->h * ratio));
} else if (autoscale == GUI::ThemeEngine::kAutoScaleNinePatch) {
Graphics::NinePatchBitmap nine(source, false);
nine.blit(*_activeSurface, r.left, r.top, r.width(), r.height());
} else {
source->blit(*_activeSurface, r.left, r.top);
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
int pixels = _activeSurface->w * _activeSurface->h;
PixelType *ptr = (PixelType *)_activeSurface->getPixels();
uint8 r, g, b;
uint lum;
// Mask to clear the last bit of every color component and all unused bits
const uint32 colorMask = ~((1 << _format.rShift) | (1 << _format.gShift) | (1 << _format.bShift) // R/G/B components
| (_format.aLoss == 8 ? 0 : (1 << _format.aShift)) // Alpha component
| ~(_alphaMask | _redMask | _greenMask | _blueMask)); // All unused bits
if (shadingStyle == GUI::ThemeEngine::kShadingDim) {
// TODO: Check how this interacts with kFeatureOverlaySupportsAlpha
for (int i = 0; i < pixels; ++i) {
*ptr = ((*ptr & colorMask) >> 1) | _alphaMask;
++ptr;
}
} else if (shadingStyle == GUI::ThemeEngine::kShadingLuminance) {
while (pixels--) {
_format.colorToRGB(*ptr, r, g, b);
lum = (r >> 2) + (g >> 1) + (b >> 3);
*ptr++ = _format.RGBToColor(lum, lum, lum);
}
}
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
if (alpha == 0xff) {
// fully opaque pixel, don't blend
*ptr = color | _alphaMask;
} else if (sizeof(PixelType) == 4) {
const byte sR = (color & _redMask) >> _format.rShift;
const byte sG = (color & _greenMask) >> _format.gShift;
const byte sB = (color & _blueMask) >> _format.bShift;
byte dR = (*ptr & _redMask) >> _format.rShift;
byte dG = (*ptr & _greenMask) >> _format.gShift;
byte dB = (*ptr & _blueMask) >> _format.bShift;
byte dA = (*ptr & _alphaMask) >> _format.aShift;
dR += ((sR - dR) * alpha) >> 8;
dG += ((sG - dG) * alpha) >> 8;
dB += ((sB - dB) * alpha) >> 8;
dA += ((0xff - dA) * alpha) >> 8;
*ptr = ((dR << _format.rShift) & _redMask)
| ((dG << _format.gShift) & _greenMask)
| ((dB << _format.bShift) & _blueMask)
| ((dA << _format.aShift) & _alphaMask);
} else if (sizeof(PixelType) == 2) {
int idst = *ptr;
int isrc = color;
*ptr = (PixelType)(
(_redMask & ((idst & _redMask) +
((int)(((int)(isrc & _redMask) -
(int)(idst & _redMask)) * alpha) >> 8))) |
(_greenMask & ((idst & _greenMask) +
((int)(((int)(isrc & _greenMask) -
(int)(idst & _greenMask)) * alpha) >> 8))) |
(_blueMask & ((idst & _blueMask) +
((int)(((int)(isrc & _blueMask) -
(int)(idst & _blueMask)) * alpha) >> 8))) |
(_alphaMask & ((idst & _alphaMask) +
((int)(((int)(_alphaMask) -
(int)(idst & _alphaMask)) * alpha) >> 8))));
} else {
error("Unsupported BPP format: %u", (uint)sizeof(PixelType));
}
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y) {
if (IS_IN_CLIP(x, y))
blendPixelPtr(ptr, color, alpha);
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
blendPixelDestAlphaPtr(PixelType *ptr, PixelType color, uint8 alpha) {
int idst = *ptr;
// This function is only used for corner pixels in rounded rectangles, so
// the performance hit of this if shouldn't be too high.
// We're also ignoring the cases where dst has intermediate alpha.
if ((idst & _alphaMask) == 0) {
// set color and alpha channels
*ptr = (PixelType)(color & (_redMask | _greenMask | _blueMask)) |
((alpha >> _format.aLoss) << _format.aShift);
} else {
// blend color with background
blendPixelPtr(ptr, color, alpha);
}
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
darkenFill(PixelType *ptr, PixelType *end) {
PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
// !kFeatureOverlaySupportsAlpha (but might have alpha bits)
while (ptr != end) {
*ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
++ptr;
}
} else {
// kFeatureOverlaySupportsAlpha
// assuming at least 3 alpha bits
mask |= 3 << _format.aShift;
PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
while (ptr != end) {
// Darken the color, and increase the alpha
// (0% -> 75%, 100% -> 100%)
*ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
++ptr;
}
}
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
darkenFillClip(PixelType *ptr, PixelType *end, int x, int y) {
PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
// !kFeatureOverlaySupportsAlpha (but might have alpha bits)
while (ptr != end) {
if (IS_IN_CLIP(x, y)) *ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
++ptr;
++x;
}
} else {
// kFeatureOverlaySupportsAlpha
// assuming at least 3 alpha bits
mask |= 3 << _format.aShift;
PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
while (ptr != end) {
// Darken the color, and increase the alpha
// (0% -> 75%, 100% -> 100%)
if (IS_IN_CLIP(x, y)) *ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
++ptr;
++x;
}
}
}
/********************************************************************
********************************************************************
* Primitive shapes drawing - Public API calls - VectorRendererSpec *
********************************************************************
********************************************************************/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area,
Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool ellipsis, const Common::Rect &textDrawableArea) {
int offset = area.top;
if (font->getFontHeight() < area.height()) {
switch (alignV) {
case GUI::ThemeEngine::kTextAlignVCenter:
offset = area.top + ((area.height() - font->getFontHeight()) >> 1);
break;
case GUI::ThemeEngine::kTextAlignVBottom:
offset = area.bottom - font->getFontHeight();
break;
default:
break;
}
}
Common::Rect drawArea;
if (textDrawableArea.isEmpty()) {
// In case no special area to draw to is given we only draw in the
// area specified by the user.
drawArea = area;
// warning("there is no text drawable area. Please set this area for clipping");
} else {
// The area we can draw to is the intersection between the allowed
// drawing area (textDrawableArea) and the area where we try to draw
// the text (area).
drawArea = textDrawableArea.findIntersectingRect(area);
}
// Better safe than sorry. We intersect with the actual surface boundaries
// to avoid any ugly clipping in _activeSurface->getSubArea which messes
// up the calculation of the x and y coordinates where to draw the string.
drawArea = drawArea.findIntersectingRect(Common::Rect(0, 0, _activeSurface->w, _activeSurface->h));
if (!drawArea.isEmpty()) {
Surface textAreaSurface = _activeSurface->getSubArea(drawArea);
font->drawString(&textAreaSurface, text, area.left - drawArea.left, offset - drawArea.top, area.width() - deltax, _fgColor, alignH, deltax, ellipsis);
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawLine(int x1, int y1, int x2, int y2) {
x1 = CLIP(x1, 0, (int)Base::_activeSurface->w);
x2 = CLIP(x2, 0, (int)Base::_activeSurface->w);
y1 = CLIP(y1, 0, (int)Base::_activeSurface->h);
y2 = CLIP(y2, 0, (int)Base::_activeSurface->h);
// we draw from top to bottom
if (y2 < y1) {
SWAP(x1, x2);
SWAP(y1, y2);
}
uint dx = ABS(x2 - x1);
uint dy = ABS(y2 - y1);
// this is a point, not a line. stoopid.
if (dy == 0 && dx == 0)
return;
if (Base::_strokeWidth == 0)
return;
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int st = Base::_strokeWidth >> 1;
bool useClippingVersions = !_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2);
int ptr_x = x1, ptr_y = y1;
if (dy == 0) { // horizontal lines
if (useClippingVersions) {
colorFillClip<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea);
} else {
colorFill<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor);
}
for (int i = 0, p = pitch; i < st; ++i, p += pitch) {
if (useClippingVersions) {
colorFillClip<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea);
colorFillClip<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea);
} else {
colorFill<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor);
colorFill<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor);
}
}
} else if (dx == 0) { // vertical lines
// these ones use a static pitch increase.
while (y1++ <= y2) {
if (useClippingVersions) {
colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea);
} else {
colorFill<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor);
}
ptr += pitch;
++ptr_y;
}
} else if (dx == dy) { // diagonal lines
// these ones also use a fixed pitch increase
pitch += (x2 > x1) ? 1 : -1;
while (dy--) {
if (useClippingVersions) {
colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea);
} else {
colorFill<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor);
}
ptr += pitch;
++ptr_y;
if (x2 > x1) ++ptr_x; else --ptr_x;
}
} else { // generic lines, use the standard algorithm...
if (useClippingVersions) {
drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
} else {
drawLineAlg(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
}
}
}
/** CIRCLES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawCircle(int x, int y, int r) {
if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h ||
x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0)
return;
bool useClippingVersions = !_clippingArea.contains(Common::Rect(x - r, y - r, x + r, y + r));
if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
&& x + r + Base::_shadowOffset < Base::_activeSurface->w
&& y + r + Base::_shadowOffset < Base::_activeSurface->h) {
if (useClippingVersions)
drawCircleAlgClip(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
else
drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
}
switch (Base::_fillMode) {
case kFillDisabled:
if (Base::_strokeWidth) {
if (useClippingVersions)
drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
else
drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
}
break;
case kFillForeground:
if (useClippingVersions)
drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
else
drawCircleAlg(x, y, r, _fgColor, kFillForeground);
break;
case kFillBackground:
if (Base::_strokeWidth > 1) {
if (useClippingVersions) {
drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
drawCircleAlgClip(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
} else {
drawCircleAlg(x, y, r, _fgColor, kFillForeground);
drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
}
} else {
if (useClippingVersions) {
drawCircleAlgClip(x, y, r, _bgColor, kFillBackground);
drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
} else {
drawCircleAlg(x, y, r, _bgColor, kFillBackground);
drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
}
}
break;
case kFillGradient:
break;
}
}
/** SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquare(int x, int y, int w, int h) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
w <= 0 || h <= 0 || x < 0 || y < 0)
return;
bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
&& x + w + Base::_shadowOffset < Base::_activeSurface->w
&& y + h + Base::_shadowOffset < Base::_activeSurface->h) {
if (useClippingVersions)
drawSquareShadowClip(x, y, w, h, Base::_shadowOffset);
else
drawSquareShadow(x, y, w, h, Base::_shadowOffset);
}
switch (Base::_fillMode) {
case kFillDisabled:
if (Base::_strokeWidth) {
if (useClippingVersions)
drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
else
drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
}
break;
case kFillForeground:
if (useClippingVersions)
drawSquareAlgClip(x, y, w, h, _fgColor, kFillForeground);
else
drawSquareAlg(x, y, w, h, _fgColor, kFillForeground);
break;
case kFillBackground:
if (useClippingVersions) {
drawSquareAlgClip(x, y, w, h, _bgColor, kFillBackground);
drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
} else {
drawSquareAlg(x, y, w, h, _bgColor, kFillBackground);
drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
}
break;
case kFillGradient:
VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient);
if (Base::_strokeWidth) {
if (useClippingVersions)
drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
else
drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
}
break;
}
}
/** ROUNDED SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawRoundedSquare(int x, int y, int r, int w, int h) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0)
return;
if ((r * 2) > w || (r * 2) > h)
r = MIN(w / 2, h / 2);
if (r <= 0)
return;
bool useOriginal = _clippingArea.contains(Common::Rect(x, y, x + w, y + h));
if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
&& x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w
&& y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h
&& h > (Base::_shadowOffset + 1) * 2) {
if (useOriginal) {
drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
} else {
drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset);
}
}
if (useOriginal) {
drawRoundedSquareAlg(x, y, r, w, h, _fgColor, Base::_fillMode);
} else {
drawRoundedSquareAlgClip(x, y, r, w, h, _fgColor, Base::_fillMode);
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTab(int x, int y, int r, int w, int h) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
return;
bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
if (r == 0 && Base::_bevel > 0) {
if (useClippingVersions)
drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
else
drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
return;
}
if (r == 0) {
return;
}
switch (Base::_fillMode) {
case kFillDisabled:
// FIXME: Implement this
return;
case kFillGradient:
case kFillBackground:
// FIXME: This is broken for the AA renderer.
// See the rounded rect alg for how to fix it. (The border should
// be drawn before the interior, both inside drawTabAlg.)
if (useClippingVersions) {
drawTabShadowClip(x, y, w - 2, h, r);
drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
if (Base::_strokeWidth)
drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
} else {
drawTabShadow(x, y, w - 2, h, r);
drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
if (Base::_strokeWidth)
drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
}
break;
case kFillForeground:
if (useClippingVersions)
drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode);
else
drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode);
break;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
return;
PixelType color = 0;
if (Base::_strokeWidth <= 1) {
if (Base::_fillMode == kFillForeground)
color = _fgColor;
else if (Base::_fillMode == kFillBackground)
color = _bgColor;
} else {
if (Base::_fillMode == kFillDisabled)
return;
color = _fgColor;
}
if (Base::_dynamicData != 0)
orient = (TriangleOrientation)Base::_dynamicData;
bool useClippingVersions = !_clippingArea.contains(Common::Rect(x, y, x + w, y + h));
if (w == h) {
int newW = w;
switch (orient) {
case kTriangleUp:
case kTriangleDown:
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
break;
case kTriangleLeft:
case kTriangleRight:
case kTriangleAuto:
break;
}
if (Base::_strokeWidth > 0)
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
}
} else {
int newW = w;
int newH = h;
switch (orient) {
case kTriangleUp:
case kTriangleDown:
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
break;
case kTriangleLeft:
case kTriangleRight:
case kTriangleAuto:
break;
}
if (Base::_strokeWidth > 0) {
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
else
drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
}
}
}
}
/********************************************************************
********************************************************************
* Aliased Primitive drawing ALGORITHMS - VectorRendererSpec
********************************************************************
********************************************************************/
/** TAB ALGORITHM - NON AA */
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
// Don't draw anything for empty rects.
if (w <= 0 || h <= 0) {
return;
}
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = 0;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
int short_h = h - r + 2;
int long_h = h;
if (fill_m == kFillDisabled) {
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
sp += pitch;
BE_RESET();
r--;
while (x++ < y) {
BE_ALGORITHM();
BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py);
if (Base::_strokeWidth > 1)
BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px - pitch, py);
}
}
ptr_fill += pitch * real_radius;
while (short_h--) {
colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color);
colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
ptr_fill += pitch;
}
if (baseLeft) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill - baseLeft, ptr_fill, color);
ptr_fill += pitch;
}
}
if (baseRight) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill, ptr_fill + baseRight, color);
ptr_fill += pitch;
}
}
} else {
BE_RESET();
precalcGradient(long_h);
PixelType color1, color2;
color1 = color2 = color;
while (x++ < y) {
BE_ALGORITHM();
if (fill_m == kFillGradient) {
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y);
gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x);
BE_DRAWCIRCLE_XCOLOR_TOP(ptr_tr, ptr_tl, x, y, px, py);
} else {
colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color);
colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color);
BE_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py);
}
}
ptr_fill += pitch * r;
while (short_h--) {
if (fill_m == kFillGradient) {
gradientFill(ptr_fill, w + 1, x1, real_radius++);
} else {
colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
}
ptr_fill += pitch;
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTabAlgClip(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
// Don't draw anything for empty rects.
if (w <= 0 || h <= 0) {
return;
}
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = 0;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int tl_x = x1 + r, tl_y = y1 + r;
int tr_x = x1 + w - r, tr_y = y1 + r;
int fill_x = x1, fill_y = y1;
int real_radius = r;
int short_h = h - r + 2;
int long_h = h;
if (fill_m == kFillDisabled) {
while (sw++ < Base::_strokeWidth) {
colorFillClip<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea);
colorFillClip<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, fill_x + r, fill_y + hp / pitch - sp / pitch, _clippingArea);
sp += pitch;
BE_RESET();
r--;
while (x++ < y) {
BE_ALGORITHM();
BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
if (Base::_strokeWidth > 1)
BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px - pitch, py, tr_x, tr_y, tl_x, tl_y);
}
}
ptr_fill += pitch * real_radius;
fill_y += real_radius;
while (short_h--) {
colorFillClip<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea);
colorFillClip<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, fill_x + w - Base::_strokeWidth + 1, fill_y, _clippingArea);
ptr_fill += pitch;
++fill_y;
}
if (baseLeft) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
fill_x = x1;
fill_y = y1 + h + 1;
while (sw++ < Base::_strokeWidth) {
colorFillClip<PixelType>(ptr_fill - baseLeft, ptr_fill, color, fill_x - baseLeft, fill_y, _clippingArea);
ptr_fill += pitch;
++fill_y;
}
}
if (baseRight) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
fill_x = x1 + w;
fill_y = y1 + h + 1;
while (sw++ < Base::_strokeWidth) {
colorFillClip<PixelType>(ptr_fill, ptr_fill + baseRight, color, fill_x, fill_y, _clippingArea);
ptr_fill += pitch;
++fill_y;
}
}
} else {
BE_RESET();
precalcGradient(long_h);
PixelType color1, color2;
color1 = color2 = color;
while (x++ < y) {
BE_ALGORITHM();
if (fill_m == kFillGradient) {
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, tl_x - x, tl_y - y);
gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, tl_x - y, tl_y - x);
BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
} else {
colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea);
colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color, tl_x - y, tl_y - x, _clippingArea);
BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
}
}
ptr_fill += pitch * r;
fill_y += r;
while (short_h--) {
if (fill_m == kFillGradient) {
gradientFillClip(ptr_fill, w + 1, x1, real_radius++, fill_x, fill_y);
} else {
colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea);
}
ptr_fill += pitch;
++fill_y;
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTabShadow(int x1, int y1, int w, int h, int r) {
int offset = 3;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
int xstart = x1;
int ystart = y1;
int width = w;
int height = h + offset + 1;
for (int i = offset; i >= 0; i--) {
int f, ddF_x, ddF_y;
int x, y, px, py;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
int short_h = height - (2 * r) + 2;
PixelType color = _format.RGBToColor(0, 0, 0);
BE_RESET();
// HACK: As we are drawing circles exploting 8-axis symmetry,
// there are 4 pixels on each circle which are drawn twice.
// this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful.
uint32 hb = 0;
while (x++ < y) {
BE_ALGORITHM();
if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
hb |= (1 << x);
}
if (((1 << y) & hb) == 0) {
blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha);
hb |= (1 << y);
}
}
ptr_fill += pitch * r;
while (short_h--) {
blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha);
ptr_fill += pitch;
}
// Move shadow one pixel upward each iteration
xstart += 1;
// Multiply with expfactor
alpha = (alpha * (expFactor << 8)) >> 9;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTabShadowClip(int x1, int y1, int w, int h, int r) {
int offset = 3;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
int xstart = x1;
int ystart = y1;
int width = w;
int height = h + offset + 1;
for (int i = offset; i >= 0; i--) {
int f, ddF_x, ddF_y;
int x, y, px, py;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
int tl_x = xstart + r, tl_y = ystart + r;
int fill_x = xstart, fill_y = ystart;
int short_h = height - (2 * r) + 2;
PixelType color = _format.RGBToColor(0, 0, 0);
BE_RESET();
// HACK: As we are drawing circles exploting 8-axis symmetry,
// there are 4 pixels on each circle which are drawn twice.
// this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful.
uint32 hb = 0;
while (x++ < y) {
BE_ALGORITHM();
if (((1 << x) & hb) == 0) {
blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, tl_x - y, tl_y - x);
hb |= (1 << x);
}
if (((1 << y) & hb) == 0) {
blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, tl_x - x, tl_y - y);
hb |= (1 << y);
}
}
ptr_fill += pitch * r;
fill_y += r;
while (short_h--) {
blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, fill_x, fill_y);
ptr_fill += pitch;
++fill_y;
}
// Move shadow one pixel upward each iteration
xstart += 1;
// Multiply with expfactor
alpha = (alpha * (expFactor << 8)) >> 9;
}
}
/** BEVELED TABS FOR CLASSIC THEME **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j;
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
i = bevel;
while (i--) {
colorFill<PixelType>(ptr_left, ptr_left + w, top_color);
ptr_left += pitch;
}
if (baseLeft > 0) {
i = h - bevel;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
while (i--) {
colorFill<PixelType>(ptr_left, ptr_left + bevel, top_color);
ptr_left += pitch;
}
}
i = h - bevel;
j = bevel - 1;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
while (i--) {
colorFill<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color);
if (j > 0) j--;
ptr_left += pitch;
}
i = bevel;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
while (i--) {
colorFill<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color);
if (baseLeft)
colorFill<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color);
ptr_left += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBevelTabAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j;
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
int ptr_x = x, ptr_y = y;
i = bevel;
while (i--) {
colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
if (baseLeft > 0) {
i = h - bevel;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
ptr_x = x; ptr_y = y;
while (i--) {
colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
}
i = h - bevel;
j = bevel - 1;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
ptr_x = x + w - bevel; ptr_y = y;
while (i--) {
colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
if (j > 0) j--;
ptr_left += pitch;
++ptr_y;
}
i = bevel;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
ptr_x = x + w - bevel; ptr_y = y + h - bevel;
while (i--) {
colorFillClip<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea);
if (baseLeft)
colorFillClip<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color, ptr_x - w - baseLeft + bevel, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
}
/** SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw anything for empty rects.
if (w <= 0 || h <= 0) {
return;
}
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int max_h = h;
if (fill_m != kFillDisabled) {
while (h--) {
if (fill_m == kFillGradient)
color = calcGradient(max_h - h, max_h);
colorFill<PixelType>(ptr, ptr + w, color);
ptr += pitch;
}
} else {
int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
while (sw--) {
colorFill<PixelType>(ptr + sp, ptr + w + sp, color);
colorFill<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color);
sp += pitch;
}
while (h--) {
colorFill<PixelType>(ptr, ptr + Base::_strokeWidth, color);
colorFill<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color);
ptr += pitch;
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquareAlgClip(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw anything for empty rects.
if (w <= 0 || h <= 0) {
return;
}
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int max_h = h;
int ptr_y = y;
if (fill_m != kFillDisabled) {
while (h--) {
if (fill_m == kFillGradient)
color = calcGradient(max_h - h, max_h);
colorFillClip<PixelType>(ptr, ptr + w, color, x, ptr_y, _clippingArea);
ptr += pitch;
++ptr_y;
}
} else {
int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
while (sw--) {
colorFillClip<PixelType>(ptr + sp, ptr + w + sp, color, x, ptr_y + sp/pitch, _clippingArea);
colorFillClip<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color, x, ptr_y + h - sp/pitch, _clippingArea);
sp += pitch;
}
while (h--) {
colorFillClip<PixelType>(ptr, ptr + Base::_strokeWidth, color, x, ptr_y, _clippingArea);
colorFillClip<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color, x + w - Base::_strokeWidth, ptr_y, _clippingArea);
ptr += pitch;
ptr_y += 1;
}
}
}
/** SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j;
PixelType *ptr_left;
// Fill Background
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
i = h;
// Optimize rendering in case the background color is black
if ((_bgColor & ~_alphaMask) == 0) {
while (i--) {
darkenFill(ptr_left, ptr_left + w);
ptr_left += pitch;
}
} else {
while (i--) {
blendFill(ptr_left, ptr_left + w, _bgColor, 200);
ptr_left += pitch;
}
}
x = MAX(x - bevel, 0);
y = MAX(y - bevel, 0);
w = MIN(x + w + (bevel * 2), (int)_activeSurface->w) - x;
h = MIN(y + h + (bevel * 2), (int)_activeSurface->h) - y;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
i = bevel;
while (i--) {
colorFill<PixelType>(ptr_left, ptr_left + w, top_color);
ptr_left += pitch;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
i = h - bevel;
while (i--) {
colorFill<PixelType>(ptr_left, ptr_left + bevel, top_color);
ptr_left += pitch;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
i = bevel;
while (i--) {
colorFill<PixelType>(ptr_left + i, ptr_left + w, bottom_color);
ptr_left += pitch;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
i = h - bevel;
j = bevel - 1;
while (i--) {
colorFill<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color);
if (j > 0) j--;
ptr_left += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBevelSquareAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j;
PixelType *ptr_left;
int ptr_x, ptr_y;
// Fill Background
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
ptr_x = x; ptr_y = y;
i = h;
// Optimize rendering in case the background color is black
if ((_bgColor & ~_alphaMask) == 0) {
while (i--) {
darkenFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y);
ptr_left += pitch;
++ptr_y;
}
} else {
while (i-- ) {
blendFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y, _bgColor, 200);
ptr_left += pitch;
}
}
x = MAX(x - bevel, 0);
y = MAX(y - bevel, 0);
w = MIN(x + w + (bevel * 2), (int)_activeSurface->w) - x;
h = MIN(y + h + (bevel * 2), (int)_activeSurface->h) - y;
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
ptr_x = x; ptr_y = y;
i = bevel;
while (i--) {
colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
ptr_x = x; ptr_y = y + bevel;
i = h - bevel;
while (i--) {
colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
ptr_x = x; ptr_y = y + h - bevel;
i = bevel;
while (i--) {
colorFillClip<PixelType>(ptr_left + i, ptr_left + w, bottom_color, ptr_x + i, ptr_y, _clippingArea);
ptr_left += pitch;
++ptr_y;
}
ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
ptr_x = x + w - bevel; ptr_y = y;
i = h - bevel;
j = bevel - 1;
while (i--) {
colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
if (j > 0) j--;
ptr_left += pitch;
++ptr_y;
}
}
/** GENERIC LINE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int xdir = (x2 > x1) ? 1 : -1;
*ptr = (PixelType)color;
if (dx > dy) {
int ddy = dy * 2;
int dysub = ddy - (dx * 2);
int error_term = ddy - dx;
while (dx--) {
if (error_term >= 0) {
ptr += pitch;
error_term += dysub;
} else {
error_term += ddy;
}
ptr += xdir;
*ptr = (PixelType)color;
}
} else {
int ddx = dx * 2;
int dxsub = ddx - (dy * 2);
int error_term = ddx - dy;
while (dy--) {
if (error_term >= 0) {
ptr += xdir;
error_term += dxsub;
} else {
error_term += ddx;
}
ptr += pitch;
*ptr = (PixelType)color;
}
}
ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
*ptr = (PixelType)color;
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int xdir = (x2 > x1) ? 1 : -1;
int ptr_x = x1, ptr_y = y1;
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
if (dx > dy) {
int ddy = dy * 2;
int dysub = ddy - (dx * 2);
int error_term = ddy - dx;
while (dx--) {
if (error_term >= 0) {
ptr += pitch;
++ptr_y;
error_term += dysub;
} else {
error_term += ddy;
}
ptr += xdir;
ptr_x += xdir;
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
}
} else {
int ddx = dx * 2;
int dxsub = ddx - (dy * 2);
int error_term = ddx - dy;
while (dy--) {
if (error_term >= 0) {
ptr += xdir;
ptr_x += xdir;
error_term += dxsub;
} else {
error_term += ddx;
}
ptr += pitch;
++ptr_y;
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
}
}
ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
ptr_x = x2; ptr_y = y2;
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
}
/** VERTICAL TRIANGLE DRAWING ALGORITHM **/
/**
FIXED POINT ARITHMETIC
**/
#define FIXED_POINT 1
#if FIXED_POINT
#define ipart(x) ((x) & ~0xFF)
// This is not really correct since gradient is not percentage, but [0..255]
#define rfpart(x) ((0x100 - ((x) & 0xFF)) * 100 >> 8)
//#define rfpart(x) (0x100 - ((x) & 0xFF))
#else
#define ipart(x) ((int)x)
#define round(x) (ipart(x + 0.5))
#define fpart(x) (x - ipart(x))
#define rfpart(x) (int)((1 - fpart(x)) * 100)
#endif
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
// Don't draw anything for empty rects. This assures dy is always different
// from zero.
if (w <= 0 || h <= 0) {
return;
}
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int gradient_h = 0;
if (!inverted) {
pitch = -pitch;
y1 += h;
}
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
PixelType *floor = ptr_right - 1;
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
int x2 = x1 + w / 2;
int y2 = y1 + h;
#if FIXED_POINT
int dx = (x2 - x1) << 8;
int dy = (y2 - y1) << 8;
if (abs(dx) > abs(dy)) {
#else
double dx = (double)x2 - (double)x1;
double dy = (double)y2 - (double)y1;
if (fabs(dx) > fabs(dy)) {
#endif
while (floor++ != ptr_left)
blendPixelPtr(floor, color, 50);
#if FIXED_POINT
// In this branch dx is always different from zero. This is because
// abs(dx) is strictly greater than abs(dy), and abs returns zero
// as minimal value.
int gradient = (dy << 8) / dx;
int intery = (y1 << 8) + gradient;
#else
double gradient = dy / dx;
double intery = y1 + gradient;
#endif
for (int x = x1 + 1; x < x2; x++) {
#if FIXED_POINT
if (intery + gradient > ipart(intery) + 0x100) {
#else
if (intery + gradient > ipart(intery) + 1) {
#endif
ptr_right++;
ptr_left--;
}
ptr_left += pitch;
ptr_right += pitch;
intery += gradient;
switch (fill_m) {
case kFillDisabled:
*ptr_left = *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFill<PixelType>(ptr_right + 1, ptr_left, color);
blendPixelPtr(ptr_right, color, rfpart(intery));
blendPixelPtr(ptr_left, color, rfpart(intery));
break;
case kFillGradient:
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
blendPixelPtr(ptr_right, color, rfpart(intery));
blendPixelPtr(ptr_left, color, rfpart(intery));
break;
}
}
return;
}
#if FIXED_POINT
if (abs(dx) < abs(dy)) {
#else
if (fabs(dx) < fabs(dy)) {
#endif
ptr_left--;
while (floor++ != ptr_left)
blendPixelPtr(floor, color, 50);
#if FIXED_POINT
int gradient = (dx << 8) / (dy + 0x100);
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / (dy + 1);
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
#if FIXED_POINT
if (interx + gradient > ipart(interx) + 0x100) {
#else
if (interx + gradient > ipart(interx) + 1) {
#endif
ptr_right++;
ptr_left--;
}
ptr_left += pitch;
ptr_right += pitch;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
*ptr_left = *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFill<PixelType>(ptr_right + 1, ptr_left, color);
blendPixelPtr(ptr_right, color, rfpart(interx));
blendPixelPtr(ptr_left, color, rfpart(interx));
break;
case kFillGradient:
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
blendPixelPtr(ptr_right, color, rfpart(interx));
blendPixelPtr(ptr_left, color, rfpart(interx));
break;
}
}
return;
}
ptr_left--;
while (floor++ != ptr_left)
blendPixelPtr(floor, color, 50);
#if FIXED_POINT
int gradient = (dx / dy) << 8;
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / dy;
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
ptr_right++;
ptr_left--;
ptr_left += pitch;
ptr_right += pitch;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
*ptr_left = *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFill<PixelType>(ptr_right + 1, ptr_left, color);
blendPixelPtr(ptr_right, color, rfpart(interx));
blendPixelPtr(ptr_left, color, rfpart(interx));
break;
case kFillGradient:
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h));
blendPixelPtr(ptr_right, color, rfpart(interx));
blendPixelPtr(ptr_left, color, rfpart(interx));
break;
}
}
}
/////////////
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleVertAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
// Don't draw anything for empty rects. This assures dy is always different
// from zero.
if (w <= 0 || h <= 0) {
return;
}
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int gradient_h = 0;
int y_pitch_sign = 1;
if (!inverted) {
pitch = -pitch;
y1 += h;
y_pitch_sign = -1;
}
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
PixelType *floor = ptr_right - 1;
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
int x2 = x1 + w / 2;
int y2 = y1 + h;
int x_right = x1;
int y_right = y1;
int x_left = x1 + w;
int y_left = y1;
int x_floor = x_right - 1;
int y_floor = y_right;
#if FIXED_POINT
int dx = (x2 - x1) << 8;
int dy = (y2 - y1) << 8;
if (abs(dx) > abs(dy)) {
#else
double dx = (double)x2 - (double)x1;
double dy = (double)y2 - (double)y1;
if (fabs(dx) > fabs(dy)) {
#endif
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
// In this branch dx is always different from zero. This is because
// abs(dx) is strictly greater than abs(dy), and abs returns zero
// as minimal value.
int gradient = (dy << 8) / dx;
int intery = (y1 << 8) + gradient;
#else
double gradient = dy / dx;
double intery = y1 + gradient;
#endif
for (int x = x1 + 1; x < x2; x++) {
#if FIXED_POINT
if (intery + gradient > ipart(intery) + 0x100) {
#else
if (intery + gradient > ipart(intery) + 1) {
#endif
ptr_right++;
ptr_left--;
++x_right;
--x_left;
}
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
intery += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
break;
}
}
return;
}
#if FIXED_POINT
if (abs(dx) < abs(dy)) {
#else
if (fabs(dx) < fabs(dy)) {
#endif
ptr_left--;
--x_left;
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
int gradient = (dx << 8) / (dy + 0x100);
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / (dy + 1);
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
#if FIXED_POINT
if (interx + gradient > ipart(interx) + 0x100) {
#else
if (interx + gradient > ipart(interx) + 1) {
#endif
ptr_right++;
ptr_left--;
++x_right;
--x_left;
}
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
}
}
return;
}
ptr_left--;
--x_left;
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
int gradient = (dx / dy) << 8;
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / dy;
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
ptr_right++;
ptr_left--;
++x_right;
--x_left;
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right + 1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
}
}
}
/////////////
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw anything for empty rects.
if (size <= 0) {
return;
}
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
if (!inverted) {
pitch = -pitch;
y1 += size;
}
int gradient_h = 0;
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + size, y1);
int x2 = x1 + size / 2;
int y2 = y1 + size;
int deltaX = abs(x2 - x1);
int deltaY = abs(y2 - y1);
int signX = x1 < x2 ? 1 : -1;
int signY = y1 < y2 ? 1 : -1;
int error = deltaX - deltaY;
colorFill<PixelType>(ptr_right, ptr_left, color);
while (1) {
switch (fill_m) {
case kFillDisabled:
*ptr_left = *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFill<PixelType>(ptr_right, ptr_left, color);
break;
case kFillGradient:
colorFill<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, size));
break;
}
if (x1 == x2 && y1 == y2)
break;
int error2 = error * 2;
if (error2 > -deltaY) {
error -= deltaY;
x1 += signX;
ptr_right += signX;
ptr_left += -signX;
}
if (error2 < deltaX) {
error += deltaX;
y1 += signY;
ptr_right += pitch;
ptr_left += pitch;
}
}
}
/** ROUNDED SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = h * pitch;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
int short_h = h - (2 * r) + 2;
PixelType color1 = color;
PixelType color2 = color;
while (sw++ < Base::_strokeWidth) {
blendFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t); // top
blendFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b); // bottom
sp += pitch;
BE_RESET();
r--;
int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
// Avoid blending the last pixels twice, since we have an alpha
while (x++ < (y - 2)) {
BE_ALGORITHM();
if (x < _clippingArea.left || x > _clippingArea.right) continue;
if (y < _clippingArea.top || y > _clippingArea.bottom) continue;
BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)));
BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)));
BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)));
BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)));
if (Base::_strokeWidth > 1) {
BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py);
BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py);
}
}
}
ptr_fill += pitch * real_radius;
while (short_h--) {
blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l); // left
blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r); // right
ptr_fill += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = h * pitch;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
int short_h = h - (2 * r) + 2;
PixelType color1 = color;
PixelType color2 = color;
while (sw++ < Base::_strokeWidth) {
blendFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t,
x1 + r, y1 + sp/pitch); // top
blendFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b,
x1 + r, y1 + (hp - sp)/ pitch); // bottom
sp += pitch;
BE_RESET();
r--;
int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
// Avoid blending the last pixels twice, since we have an alpha
while (x++ < (y - 2)) {
BE_ALGORITHM();
BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)), x1 + w - r, y1 + r);
BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)), x1 + w - r, y1 + h - r);
BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)), x1 + r, y1 + h - r);
BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)), x1 + r, y1 + r);
BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)), x1 + w - r, y1 + r);
BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)), x1 + w - r, y1 + h - r);
BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)), x1 + r, y1 + h - r);
BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)), x1 + r, y1 + r);
if (Base::_strokeWidth > 1) {
BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py,
x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py,
x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
}
}
}
ptr_fill += pitch * real_radius;
while (short_h--) {
blendFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l,
x1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // left
blendFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r,
x1 + w - Base::_strokeWidth + 1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // right
ptr_fill += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
return;
}
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
int short_h = h - (2 * r) + 2;
int long_h = h;
BE_RESET();
PixelType color1 = color;
if (fill_m == kFillGradient) {
PixelType color2, color3, color4;
precalcGradient(long_h);
while (x++ < y) {
BE_ALGORITHM();
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
color3 = calcGradient(long_h - r + x, long_h);
color4 = calcGradient(long_h - r + y, long_h);
gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y);
gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x);
gradientFill(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y);
gradientFill(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x);
BE_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
}
} else {
while (x++ < y) {
BE_ALGORITHM();
colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1);
colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1);
colorFill<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1);
colorFill<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1);
// do not remove - messes up the drawing at lower resolutions
BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py);
}
}
ptr_fill += pitch * r;
while (short_h--) {
if (fill_m == kFillGradient) {
gradientFill(ptr_fill, w + 1, x1, real_radius++);
} else {
colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color1);
}
ptr_fill += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
return;
}
int f, ddF_x, ddF_y;
int x, y, px, py;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
int short_h = h - (2 * r) + 2;
int long_h = h;
BE_RESET();
PixelType color1 = color;
if (fill_m == kFillGradient) {
PixelType color2, color3, color4;
precalcGradient(long_h);
while (x++ < y) {
BE_ALGORITHM();
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
color3 = calcGradient(long_h - r + x, long_h);
color4 = calcGradient(long_h - r + y, long_h);
//TL = (x1 + r, y1 + r)
gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y,
x1 + r - x, y1 + r - y);
gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x,
x1 + r - y, y1 + r - x);
//BL = (x1 + r, y1 + h - r)
gradientFillClip(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y,
x1 + r - x, y1 + h - r + y);
gradientFillClip(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x,
x1 + r - y, y1 + h - r + x);
BE_DRAWCIRCLE_XCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
}
} else {
while (x++ < y) {
BE_ALGORITHM();
colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1,
x1 + r - x, y1 + r - y, _clippingArea);
colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1,
x1 + r - y, y1 + r - x, _clippingArea);
colorFillClip<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1,
x1 + r - x, y1 + h - r + y, _clippingArea);
colorFillClip<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1,
x1 + r - y, y1 + h - r + x, _clippingArea);
// do not remove - messes up the drawing at lower resolutions
BE_DRAWCIRCLE_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
}
}
ptr_fill += pitch * r;
int short_h_orig = short_h;
while (short_h--) {
if (fill_m == kFillGradient) {
gradientFillClip(ptr_fill, w + 1, x1, real_radius++, x1, y1 + r + short_h_orig - short_h -1);
} else {
colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color1, x1, y1 + r + short_h_orig - short_h - 1, _clippingArea);
}
ptr_fill += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255;
const uint8 bevelAlpha_r = 31;
const uint8 bevelAlpha_b = 0;
const uint8 bevelAlpha_l = 127;
// If only border is visible
if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
if (fill_m == Base::kFillBackground)
drawInteriorRoundedSquareAlg(x1, y1, r, w, h, _bgColor, fill_m);
else
drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m);
}
if (Base::_strokeWidth) {
if (r != 0 && _bevel > 0) {
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
drawBorderRoundedSquareAlg(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
} else {
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255;
const uint8 bevelAlpha_r = 31;
const uint8 bevelAlpha_b = 0;
const uint8 bevelAlpha_l = 127;
// If only border is visible
if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
if (fill_m == Base::kFillBackground)
drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, _bgColor, fill_m);
else
drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m);
}
//I expect these to work fine with clipping:
if (Base::_strokeWidth) {
if (r != 0 && _bevel > 0) {
drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
} else {
drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
}
}
}
/** CIRCLE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
int f, ddF_x, ddF_y;
int x, y, px, py, sw = 0;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
if (fill_m == kFillDisabled) {
while (sw++ < Base::_strokeWidth) {
BE_RESET();
r--;
*(ptr + y) = color;
*(ptr - y) = color;
*(ptr + py) = color;
*(ptr - py) = color;
while (x++ < y) {
BE_ALGORITHM();
BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py);
if (Base::_strokeWidth > 1) {
BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x - 1, y, px, py);
BE_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px - pitch, py);
}
}
}
} else {
colorFill<PixelType>(ptr - r, ptr + r, color);
BE_RESET();
while (x++ < y) {
BE_ALGORITHM();
colorFill<PixelType>(ptr - x + py, ptr + x + py, color);
colorFill<PixelType>(ptr - x - py, ptr + x - py, color);
colorFill<PixelType>(ptr - y + px, ptr + y + px, color);
colorFill<PixelType>(ptr - y - px, ptr + y - px, color);
}
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawCircleAlgClip(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
int f, ddF_x, ddF_y;
int x, y, px, py, sw = 0;
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
if (fill_m == kFillDisabled) {
while (sw++ < Base::_strokeWidth) {
BE_RESET();
r--;
if (IS_IN_CLIP(x1 + y, y1)) *(ptr + y) = color;
if (IS_IN_CLIP(x1 - y, y1)) *(ptr - y) = color;
if (IS_IN_CLIP(x1, y1 + y)) *(ptr + py) = color;
if (IS_IN_CLIP(x1, y1 - y)) *(ptr - py) = color;
while (x++ < y) {
BE_ALGORITHM();
BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
if (Base::_strokeWidth > 1) {
BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x - 1, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px - pitch, py, x1, y1, x1, y1, x1, y1, x1, y1);
}
}
}
} else {
colorFillClip<PixelType>(ptr - r, ptr + r, color, x1 - r, y1 + r, _clippingArea);
BE_RESET();
while (x++ < y) {
BE_ALGORITHM();
colorFillClip<PixelType>(ptr - x + py, ptr + x + py, color, x1 - x, y1 + y, _clippingArea);
colorFillClip<PixelType>(ptr - x - py, ptr + x - py, color, x1 - x, y1 - y, _clippingArea);
colorFillClip<PixelType>(ptr - y + px, ptr + y + px, color, x1 - y, y1 + x, _clippingArea);
colorFillClip<PixelType>(ptr - y - px, ptr + y - px, color, x1 - y, y1 - x, _clippingArea);
}
}
}
/********************************************************************
********************************************************************
* SHADOW drawing algorithms - VectorRendererSpec *******************
********************************************************************
********************************************************************/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquareShadow(int x, int y, int w, int h, int offset) {
// Do nothing for empty rects or no shadow offset.
if (w <= 0 || h <= 0 || offset <= 0) {
return;
}
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j;
i = h - offset;
while (i--) {
j = offset;
while (j--)
blendPixelPtr(ptr + j, 0, ((offset - j) << 8) / offset);
ptr += pitch;
}
ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
while (i++ < offset) {
j = w - offset;
while (j--)
blendPixelPtr(ptr + j, 0, ((offset - i) << 8) / offset);
ptr += pitch;
}
ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
i = 0;
while (i++ < offset) {
j = offset - 1;
while (j--)
blendPixelPtr(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset));
ptr += pitch;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawSquareShadowClip(int x, int y, int w, int h, int offset) {
// Do nothing for empty rects or no shadow offset.
if (w <= 0 || h <= 0 || offset <= 0) {
return;
}
PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int i, j, ptr_x = x+w-1, ptr_y = y+offset;
i = h - offset;
while (i--) {
j = offset;
while (j--)
blendPixelPtrClip(ptr + j, 0, ((offset - j) << 8) / offset, ptr_x + j, ptr_y);
ptr += pitch;
++ptr_y;
}
ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
ptr_x = x + offset;
ptr_y = y + h - 1;
while (i++ < offset) {
j = w - offset;
while (j--)
blendPixelPtrClip(ptr + j, 0, ((offset - i) << 8) / offset, ptr_x + j, ptr_y);
ptr += pitch;
++ptr_y;
}
ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
ptr_x = x + w;
ptr_y = y + h;
i = 0;
while (i++ < offset) {
j = offset - 1;
while (j--)
blendPixelPtrClip(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset), ptr_x + j, ptr_y);
ptr += pitch;
++ptr_y;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
// These constants ensure a border of 2px on the left and of each rounded square
Common::Rect shadowRect(w + offset + 2, h + offset + 1);
shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1);
// The rounded rectangle drawn on top of this shadow is guaranteed
// to occlude entirely the following rect with a non-transparent color.
// As an optimization, we don't draw the shadow inside of it.
Common::Rect occludingRect(x1, y1, x1 + w, y1 + h);
occludingRect.top += r;
occludingRect.bottom -= r;
// Soft shadows are constructed by drawing increasingly
// darker and smaller rectangles on top of each other.
for (int i = offset; i >= 0; i--) {
int f, ddF_x, ddF_y;
int x, y, px, py;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.top + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.bottom - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r);
PixelType color = _format.RGBToColor(0, 0, 0);
BE_RESET();
// HACK: As we are drawing circles exploiting 8-axis symmetry,
// there are 4 pixels on each circle which are drawn twice.
// this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful.
uint32 hb = 0;
// Draw the top and bottom parts of the shadow. Those parts have rounded corners.
while (x++ < y) {
BE_ALGORITHM();
if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha);
hb |= (1 << x);
}
if (((1 << y) & hb) == 0) {
blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha);
blendFill(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha);
hb |= (1 << y);
}
}
// Draw the middle part of the shadow. This part is a rectangle with regular corners.
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r);
for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) {
if (occludingRect.top <= y2 && y2 < occludingRect.bottom) {
if (shadowRect.left < occludingRect.left) {
blendFill(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha);
}
if (occludingRect.right < shadowRect.right + 1) {
blendFill(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha);
}
} else {
blendFill(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha);
}
ptr_fill += pitch;
}
// Make shadow smaller each iteration
shadowRect.grow(-1);
if (_shadowFillMode == kShadowExponential)
// Multiply with expfactor
alpha = (alpha * (expFactor << 8)) >> 9;
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
// "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
uint8 expFactor = 3;
uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
// These constants ensure a border of 2px on the left and of each rounded square
Common::Rect shadowRect(w + offset + 2, h + offset + 1);
shadowRect.translate((x1 > 2) ? x1 - 2 : x1, y1);
// The rounded rectangle drawn on top of this shadow is guaranteed
// to occlude entirely the following rect with a non-transparent color.
// As an optimization, we don't draw the shadow inside of it.
Common::Rect occludingRect(x1, y1, x1 + w, y1 + h);
occludingRect.top += r;
occludingRect.bottom -= r;
// Soft shadows are constructed by drawing increasingly
// darker and smaller rectangles on top of each other.
for (int i = offset; i >= 0; i--) {
int f, ddF_x, ddF_y;
int x, y, px, py;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.top + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.top + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.left + r, shadowRect.bottom - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(shadowRect.right - r, shadowRect.bottom - r);
PixelType color = _format.RGBToColor(0, 0, 0);
BE_RESET();
// HACK: As we are drawing circles exploiting 8-axis symmetry,
// there are 4 pixels on each circle which are drawn twice.
// this is ok on filled circles, but when blending on surfaces,
// we cannot let it blend twice. awful.
uint32 hb = 0;
while (x++ < y) {
BE_ALGORITHM();
if (((1 << x) & hb) == 0) {
blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha,
shadowRect.left + r - y, shadowRect.top + r - x);
blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha,
shadowRect.left + r - y, shadowRect.bottom - r + x);
hb |= (1 << x);
}
if (((1 << y) & hb) == 0) {
blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha,
shadowRect.left + r - x, shadowRect.top + r - y);
blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha,
shadowRect.left + r - x, shadowRect.bottom - r + y);
hb |= (1 << y);
}
}
// Draw the middle part of the shadow. This part is a rectangle with regular corners.
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(0, shadowRect.top + r);
for (int y2 = shadowRect.top + r; y2 < shadowRect.bottom - r + 1; y2++) {
if (occludingRect.top <= y2 && y2 < occludingRect.bottom) {
if (shadowRect.left < occludingRect.left) {
blendFillClip(ptr_fill + shadowRect.left, ptr_fill + occludingRect.left, color, (uint8)alpha,
shadowRect.left, y2);
}
if (occludingRect.right < shadowRect.right + 1) {
blendFillClip(ptr_fill + occludingRect.right, ptr_fill + shadowRect.right + 1, color, (uint8)alpha,
occludingRect.right, y2);
}
} else {
blendFillClip(ptr_fill + shadowRect.left, ptr_fill + shadowRect.right + 1, color, (uint8)alpha,
shadowRect.left, y2);
}
ptr_fill += pitch;
}
// Make shadow smaller each iteration
shadowRect.grow(-1);
if (_shadowFillMode == kShadowExponential)
// Multiply with expfactor
alpha = (alpha * (expFactor << 8)) >> 9;
}
}
/******************************************************************************/
#ifndef DISABLE_FANCY_THEMES
/********************************************************************
* ANTIALIASED PRIMITIVES drawing algorithms - VectorRendererAA
********************************************************************/
/** LINES **/
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int xdir = (x2 > x1) ? 1 : -1;
uint16 error_tmp, error_acc, gradient;
uint8 alpha;
*ptr = (PixelType)color;
if (dx > dy) {
gradient = (dy << 16) / dx;
error_acc = 0;
while (--dx) {
error_tmp = error_acc;
error_acc += gradient;
if (error_acc <= error_tmp)
ptr += pitch;
ptr += xdir;
alpha = (error_acc >> 8);
this->blendPixelPtr(ptr, color, ~alpha);
this->blendPixelPtr(ptr + pitch, color, alpha);
}
} else if (dy != 0) {
gradient = (dx << 16) / dy;
error_acc = 0;
while (--dy) {
error_tmp = error_acc;
error_acc += gradient;
if (error_acc <= error_tmp)
ptr += xdir;
ptr += pitch;
alpha = (error_acc >> 8);
this->blendPixelPtr(ptr, color, ~alpha);
this->blendPixelPtr(ptr + xdir, color, alpha);
}
}
Base::putPixel(x2, y2, color);
}
/** TAB ALGORITHM */
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
// Don't draw anything for empty rects.
if (w <= 0 || h <= 0) {
return;
}
int x, y, px, py;
int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int sw = 0, sp = 0, hp = 0;
frac_t T = 0, oldT;
uint8 a1, a2;
uint32 rsq = r*r;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int real_radius = r;
if (fill_m == Base::kFillDisabled) {
color = 0;
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color);
colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color);
sp += pitch;
x = r - (sw - 1);
y = 0;
T = 0;
px = pitch * x;
py = 0;
while (x > y++) {
WU_ALGORITHM();
// sw == 1: outside, sw = _strokeWidth: inside
if (sw != Base::_strokeWidth)
a2 = 255;
// inner arc
WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py, a2);
if (sw == 1) // outer arc
WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px - pitch, py, a1);
}
}
int short_h = h - r + 2;
ptr_fill += pitch * real_radius;
while (short_h--) {
colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color);
colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color);
ptr_fill += pitch;
}
if (baseLeft) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill - baseLeft, ptr_fill, color);
ptr_fill += pitch;
}
}
if (baseRight) {
sw = 0;
ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
while (sw++ < Base::_strokeWidth) {
colorFill<PixelType>(ptr_fill, ptr_fill + baseRight, color);
ptr_fill += pitch;
}
}
} else {
PixelType color1, color2;
color1 = color2 = color;
int long_h = h;
int short_h = h - real_radius + 2;
x = real_radius;
y = 0;
T = 0;
px = pitch * x;
py = 0;
Base::precalcGradient(long_h);
while (x > y++) {
WU_ALGORITHM();
if (fill_m == Base::kFillGradient) {
color1 = Base::calcGradient(real_radius - x, long_h);
color2 = Base::calcGradient(real_radius - y, long_h);
Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, real_radius - y);
// Only fill each horizontal line once (or we destroy
// the gradient effect at the edges)
if (T < oldT || y == 1)
Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, real_radius - x);
WU_DRAWCIRCLE_XCOLOR_TOP(ptr_tr, ptr_tl, x, y, px, py, a1, Base::blendPixelPtr);
} else {
colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color);
if (T < oldT || y == 1)
colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color);
WU_DRAWCIRCLE_TOP(ptr_tr, ptr_tl, x, y, px, py, a1);
}
}
ptr_fill += pitch * r;
while (short_h--) {
if (fill_m == Base::kFillGradient) {
Base::gradientFill(ptr_fill, w + 1, x1, real_radius++);
} else {
colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
}
ptr_fill += pitch;
}
}
}
/** ROUNDED SQUARES **/
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
int x, y;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py;
uint32 rsq = r*r;
frac_t T = 0, oldT;
uint8 a1, a2;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int sw = 0, sp = 0;
int short_h = h - 2 * r;
int hp = h * pitch;
int strokeWidth = Base::_strokeWidth;
while (sw++ < strokeWidth) {
this->blendFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, alpha_b); // bottom
this->blendFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, alpha_t); // top
sp += pitch;
x = r - (sw - 1);
y = 0;
T = 0;
px = pitch * x;
py = 0;
int alphaStep_tr = ((alpha_t - alpha_r) / (x + 1));
int alphaStep_br = ((alpha_r - alpha_b) / (x + 1));
int alphaStep_bl = ((alpha_b - alpha_l) / (x + 1));
int alphaStep_tl = ((alpha_l - alpha_t) / (x + 1));
while (x > y++) {
WU_ALGORITHM();
// sw == 1: outside, sw = _strokeWidth: inside
// We always draw the outer edge AAed, but the inner edge
// only when the inside isn't filled
if (sw != strokeWidth || fill_m != Base::kFillDisabled)
a2 = 255;
// inner arc
WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a2) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a2) >> 16));
// outer arc
if (sw == 1) {
WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a1) >> 16));
WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a1) >> 16));
}
}
ptr_fill += pitch * r;
while (short_h-- >= -2) {
this->blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color, alpha_l); // left
this->blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, alpha_r); // right
ptr_fill += pitch;
}
}
}
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
w -= 2*Base::_strokeWidth;
h -= 2*Base::_strokeWidth;
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
return;
}
int x, y;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py;
uint32 rsq = r*r;
frac_t T = 0, oldT;
uint8 a1, a2;
r -= Base::_strokeWidth;
x1 += Base::_strokeWidth;
y1 += Base::_strokeWidth;
rsq = r*r;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
int short_h = h - 2 * r;
x = r;
y = 0;
T = 0;
px = pitch * x;
py = 0;
if (fill_m == Base::kFillGradient) {
Base::precalcGradient(h);
PixelType color1, color2, color3, color4;
while (x > y++) {
WU_ALGORITHM();
color1 = Base::calcGradient(r - x, h);
color2 = Base::calcGradient(r - y, h);
color3 = Base::calcGradient(h - r + x, h);
color4 = Base::calcGradient(h - r + y, h);
Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, r - y);
// Only fill each horizontal line once (or we destroy
// the gradient effect at the edges)
if (T < oldT || y == 1)
Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, r - x);
Base::gradientFill(ptr_bl - x + py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, h - r + y);
// Only fill each horizontal line once (or we destroy
// the gradient effect at the edges)
if (T < oldT || y == 1)
Base::gradientFill(ptr_bl - y + px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, h - r + x);
// This shape is used for dialog backgrounds.
// If we're drawing on top of an empty overlay background,
// and the overlay supports alpha, we have to do AA by
// setting the dest alpha channel, instead of blending with
// dest color channels.
if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha))
WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelPtr);
else
WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelDestAlphaPtr);
}
ptr_fill += pitch * r;
while (short_h-- >= 0) {
Base::gradientFill(ptr_fill, w + 1, x1, r++);
ptr_fill += pitch;
}
} else {
while (x > 1 + y++) {
WU_ALGORITHM();
colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color);
if (T < oldT || y == 1)
colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color);
colorFill<PixelType>(ptr_bl - x + py + 1, ptr_br + x + py, color);
if (T < oldT || y == 1)
colorFill<PixelType>(ptr_bl - y + px + 1, ptr_br + y + px, color);
WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1);
}
ptr_fill += pitch * r;
while (short_h-- >= 0) {
colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color);
ptr_fill += pitch;
}
}
}
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
const uint8 borderAlpha_b = 255;
const uint8 borderAlpha_l = 63;
const uint8 bevelAlpha_t = 255;
const uint8 bevelAlpha_r = 31;
const uint8 bevelAlpha_b = 0;
const uint8 bevelAlpha_l = 127;
if (Base::_strokeWidth) {
if (r != 0 && Base::_bevel > 0) {
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
drawBorderRoundedSquareAlg(x1, y1, r, w, h, Base::_bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
} else {
drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
}
}
// If only border is visible
if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
if (fill_m == Base::kFillBackground)
drawInteriorRoundedSquareAlg(x1, y1, r, w, h, Base::_bgColor, fill_m);
else
drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m);
}
}
/** CIRCLES **/
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
int x, y, sw = 0;
const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel;
int px, py;
uint32 rsq = r*r;
frac_t T = 0, oldT;
uint8 a1, a2;
PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
if (fill_m == VectorRenderer::kFillDisabled) {
while (sw++ < Base::_strokeWidth) {
x = r - (sw - 1);
y = 0;
T = 0;
px = pitch * x;
py = 0;
*(ptr + x) = (PixelType)color;
*(ptr - x) = (PixelType)color;
*(ptr + px) = (PixelType)color;
*(ptr - px) = (PixelType)color;
while (x > y++) {
WU_ALGORITHM();
if (sw != 1 && sw != Base::_strokeWidth)
a2 = a1 = 255;
WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, (x - 1), y, (px - pitch), py, a2);
WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
}
}
} else {
colorFill<PixelType>(ptr - r, ptr + r + 1, color);
x = r;
y = 0;
T = 0;
px = pitch * x;
py = 0;
while (x > y++) {
WU_ALGORITHM();
colorFill<PixelType>(ptr - x + py, ptr + x + py, color);
colorFill<PixelType>(ptr - x - py, ptr + x - py, color);
colorFill<PixelType>(ptr - y + px, ptr + y + px, color);
colorFill<PixelType>(ptr - y - px, ptr + y - px, color);
WU_DRAWCIRCLE(ptr, ptr, ptr, ptr, x, y, px, py, a1);
}
}
}
#endif
}