mirror of
https://github.com/libretro/scummvm.git
synced 2026-11-07 12:38:04 -10:00
Such a shadow was dropped completely, on all four sides, while the GUI
still reserved and restored the space for it. In the compact layout this
is every dialog that fills the screen: the file browser, the game
chooser, the theme browser, the mass add dialog and the options dialog.
The test became one pixel stricter than the drawing needs in
af289bdb03, which dropped an x++; y++; w--; h--; from the top of the
function and tightened the test to compensate. Nothing needed
compensating: (x + 1) + (w - 1) is x + w, so the tested quantity never
moved.
4461 lines
134 KiB
C++
4461 lines
134 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/util.h"
|
|
#include "common/system.h"
|
|
#include "common/frac.h"
|
|
|
|
#include "graphics/managed_surface.h"
|
|
#include "graphics/nine_patch.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 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.
|
|
*
|
|
* @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) {
|
|
static_assert(sizeof(PixelType) == 1 || sizeof(PixelType) == 2 || sizeof(PixelType) == 4, "Unsupported PixelType");
|
|
|
|
int count = (last - first);
|
|
|
|
if (sizeof(PixelType) == 1)
|
|
memset((uint8 *)first, color, count);
|
|
else if (sizeof(PixelType) == 2)
|
|
Common::memset16((uint16 *)first, color, count);
|
|
else
|
|
Common::memset32((uint32 *)first, color, count);
|
|
}
|
|
|
|
template<typename PixelType>
|
|
void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
|
|
static_assert(sizeof(PixelType) == 1 || sizeof(PixelType) == 2 || sizeof(PixelType) == 4, "Unsupported PixelType");
|
|
|
|
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 (sizeof(PixelType) == 1)
|
|
memset((uint8 *)first, color, count);
|
|
else if (sizeof(PixelType) == 2)
|
|
Common::memset16((uint16 *)first, color, count);
|
|
else
|
|
Common::memset32((uint32 *)first, color, count);
|
|
}
|
|
|
|
/**
|
|
* Fills several pixels in a column with a given color.
|
|
*
|
|
* @param first Pointer to the first pixel to fill.
|
|
* @param last Pointer to the last pixel to fill.
|
|
* @param pitch Number of pixels in a line.
|
|
* @param color Color of the pixel
|
|
*/
|
|
template<typename PixelType>
|
|
void colorVFill(PixelType *first, PixelType *last, int pitch, PixelType color) {
|
|
int count = (last - first) / pitch;
|
|
if (!count)
|
|
return;
|
|
for (PixelType *p = first; count; p+= pitch, count--) {
|
|
*p = color;
|
|
}
|
|
}
|
|
|
|
template<typename PixelType>
|
|
void colorVFillClip(PixelType *first, PixelType *last, int pitch, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
|
|
if (realX < clippingArea.left || realX >= clippingArea.right)
|
|
return;
|
|
|
|
int count = (last - first) / pitch;
|
|
|
|
if (realY > clippingArea.bottom || realY + count < clippingArea.top)
|
|
return;
|
|
|
|
if (realY < clippingArea.top) {
|
|
int diff = (clippingArea.top - realY);
|
|
realY += diff;
|
|
first += diff * pitch;
|
|
count -= diff;
|
|
}
|
|
|
|
if (clippingArea.bottom <= realY + count) {
|
|
int diff = (realY + count - clippingArea.bottom);
|
|
count -= diff;
|
|
}
|
|
|
|
if (!count)
|
|
return;
|
|
|
|
for (PixelType *p = first; count; p+= pitch, count--) {
|
|
*p = color;
|
|
}
|
|
}
|
|
|
|
|
|
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);
|
|
else if (g_system->getOverlayFormat().bytesPerPixel == 1)
|
|
return new VectorRendererSpec<uint8>(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);
|
|
// No AA with 8-bit
|
|
else if (g_system->getOverlayFormat().bytesPerPixel == 1)
|
|
return new VectorRendererSpec<uint8>(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) {
|
|
|
|
_clippingArea = Common::Rect(0, 0, 32767, 32767);
|
|
|
|
_fgColor = _bgColor = _bevelColor = 0;
|
|
_gradientStart = _gradientEnd = 0;
|
|
}
|
|
|
|
/****************************
|
|
* 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
|
|
colorFillClip<PixelType>(ptr, ptr + width, _gradCache[curGrad], realX, realY, _clippingArea);
|
|
} else if (grad == 3 && ox) {
|
|
colorFillClip<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1], realX, realY, _clippingArea);
|
|
} 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::ManagedSurface *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>::
|
|
blitManagedSurface(const Graphics::ManagedSurface *source, const Common::Point &p, Graphics::AlphaType alphaType) {
|
|
Common::Rect drawRect(p.x, p.y, p.x + source->w, p.y + source->h);
|
|
drawRect.clip(_clippingArea);
|
|
drawRect.translate(-p.x, -p.y);
|
|
|
|
if (drawRect.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
Common::Point np;
|
|
if (!_clippingArea.contains(p)) {
|
|
int16 nx = CLIP(p.x, _clippingArea.left, _clippingArea.right);
|
|
int16 ny = CLIP(p.y, _clippingArea.top, _clippingArea.bottom);
|
|
np = Common::Point(nx, ny);
|
|
} else {
|
|
np = p;
|
|
}
|
|
|
|
if (_activeSurface->format.bytesPerPixel == 1 && alphaType != Graphics::ALPHA_OPAQUE) {
|
|
// simpleBlitFrom doesn't currently support alpha blending to an RGB332 surface.
|
|
_activeSurface->transBlitFrom(*source, drawRect, np);
|
|
} else {
|
|
_activeSurface->simpleBlitFrom(*source, drawRect, np, Graphics::FLIP_NONE, alphaType != Graphics::ALPHA_OPAQUE);
|
|
}
|
|
}
|
|
|
|
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 if (sizeof(PixelType) == 1) {
|
|
if (alpha & 0x80)
|
|
*ptr = color;
|
|
} 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)
|
|
|
|
mask |= _alphaMask;
|
|
|
|
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)
|
|
|
|
mask |= _alphaMask;
|
|
|
|
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::U32String &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()) {
|
|
Common::Rect textArea(area);
|
|
textArea.right -= deltax;
|
|
|
|
Surface textAreaSurface = _activeSurface->getSubArea(drawArea);
|
|
|
|
if (deltax >= 0) {
|
|
textArea.left += deltax;
|
|
deltax = 0;
|
|
}
|
|
|
|
font->drawString(&textAreaSurface, text, textArea.left - drawArea.left, offset - drawArea.top, textArea.width(), _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;
|
|
// Stroke widths before and after the coordinate
|
|
// Before is favoured in case of even stroke width
|
|
int stb = Base::_strokeWidth >> 1;
|
|
int sta = stb + (Base::_strokeWidth & 1);
|
|
|
|
bool useClippingVersions = !_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2);
|
|
|
|
if (dy == 0) { // horizontal lines
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
if (useClippingVersions) {
|
|
colorFillClip<PixelType>(ptr + p, ptr + p + dx + 1, (PixelType)_fgColor, x1, y1 + i, _clippingArea);
|
|
} else {
|
|
colorFill<PixelType>(ptr + p, ptr + p + dx + 1, (PixelType)_fgColor);
|
|
}
|
|
}
|
|
|
|
} else if (dx == 0) { // vertical lines
|
|
// these ones use a static pitch increase.
|
|
while (y1 <= y2) {
|
|
if (useClippingVersions) {
|
|
colorFillClip<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor, x1 - stb, y1, _clippingArea);
|
|
} else {
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor);
|
|
}
|
|
ptr += pitch;
|
|
y1++;
|
|
}
|
|
|
|
} 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 - stb, ptr + sta, (PixelType)_fgColor, x1 - stb, y1, _clippingArea);
|
|
} else {
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor);
|
|
}
|
|
ptr += pitch;
|
|
y1++;
|
|
if (x2 > x1) ++x1; else --x1;
|
|
}
|
|
|
|
} 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 + 1, y + r + 1));
|
|
|
|
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;
|
|
|
|
default:
|
|
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;
|
|
|
|
default:
|
|
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 + 1, y + h + 1));
|
|
|
|
if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
|
|
&& x + w + Base::_shadowOffset < Base::_activeSurface->w
|
|
&& y + h + Base::_shadowOffset < Base::_activeSurface->h
|
|
&& h > (Base::_shadowOffset + 1) * 2) {
|
|
if (useOriginal) {
|
|
drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset, Base::_shadowIntensity);
|
|
} else {
|
|
drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset, Base::_shadowIntensity);
|
|
}
|
|
}
|
|
|
|
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, int s) {
|
|
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));
|
|
uint32 baseLeft = (Base::_dynamicData >> 16) & 0x7FFF;
|
|
uint32 baseRight = Base::_dynamicData & 0xFFFF;
|
|
bool vFlip = (Base::_dynamicData >> 31) != 0;
|
|
|
|
if (r == 0 && Base::_bevel > 0) {
|
|
if (useClippingVersions)
|
|
drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, baseLeft, baseRight, vFlip);
|
|
else
|
|
drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, baseLeft, baseRight, vFlip);
|
|
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, s, Base::_shadowIntensity, vFlip);
|
|
drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode, 0, 0, vFlip);
|
|
if (Base::_strokeWidth)
|
|
drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, baseLeft, baseRight, vFlip);
|
|
} else {
|
|
drawTabShadow(x, y, w - 2, h, r, s, Base::_shadowIntensity, vFlip);
|
|
drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode, 0, 0, vFlip);
|
|
if (Base::_strokeWidth)
|
|
drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, baseLeft, baseRight, vFlip);
|
|
}
|
|
break;
|
|
|
|
case kFillForeground:
|
|
if (useClippingVersions)
|
|
drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode, 0, 0, vFlip);
|
|
else
|
|
drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode, 0, 0, vFlip);
|
|
break;
|
|
|
|
default:
|
|
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));
|
|
|
|
void (VectorRendererSpec<PixelType>::*drawFunc)(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) = nullptr;
|
|
bool inverted = false;
|
|
|
|
switch (orient) {
|
|
case kTriangleUp:
|
|
case kTriangleDown:
|
|
if (useClippingVersions)
|
|
drawFunc = &VectorRendererSpec<PixelType>::drawTriangleVertAlgClip;
|
|
else
|
|
drawFunc = &VectorRendererSpec<PixelType>::drawTriangleVertAlg;
|
|
inverted = (orient == kTriangleDown);
|
|
break;
|
|
|
|
case kTriangleLeft:
|
|
case kTriangleRight:
|
|
if (useClippingVersions)
|
|
drawFunc = &VectorRendererSpec<PixelType>::drawTriangleHorzAlgClip;
|
|
else
|
|
drawFunc = &VectorRendererSpec<PixelType>::drawTriangleHorzAlg;
|
|
inverted = (orient == kTriangleRight);
|
|
break;
|
|
case kTriangleAuto:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (drawFunc) {
|
|
(this->*drawFunc)(x, y, w, h, inverted, color, Base::_fillMode);
|
|
if (Base::_strokeWidth > 0) {
|
|
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
|
|
(this->*drawFunc)(x, y, w, h, inverted, _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, bool vFlip) {
|
|
// 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;
|
|
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, bool vFlip) {
|
|
// 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;
|
|
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, uint32 shadowIntensity, bool vFlip) {
|
|
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;
|
|
|
|
// HACK: shadowIntensity is tailed with 16-bits mantissa. We also represent the
|
|
// offset as a 16.16 fixed point number here as termination condition to simplify
|
|
// looping logic. An additional `shadowIntensity` is added to to keep consistent
|
|
// with previous implementation.
|
|
uint32 targetOffset = (uint32)(offset << 16) + shadowIntensity;
|
|
int curOffset = 0;
|
|
for (uint32 i = shadowIntensity; i <= targetOffset; i += shadowIntensity) {
|
|
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);
|
|
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 upward each iteration
|
|
xstart += (i >> 16) - curOffset;
|
|
curOffset = i >> 16;
|
|
// 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, uint32 shadowIntensity, bool vFlip) {
|
|
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;
|
|
|
|
// HACK: shadowIntensity is tailed with 16-bits mantissa. We also represent the
|
|
// offset as a 16.16 fixed point number here as termination condition to simplify
|
|
// looping logic. An additional `shadowIntensity` is added to to keep consistent
|
|
// with previous implementation.
|
|
uint32 targetOffset = (uint32)(offset << 16) + shadowIntensity;
|
|
int curOffset = 0;
|
|
for (uint32 i = shadowIntensity; i <= targetOffset; i += shadowIntensity) {
|
|
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);
|
|
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 += (i >> 16) - curOffset;
|
|
curOffset = i >> 16;
|
|
// 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, bool vFlip) {
|
|
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, bool vFlip) {
|
|
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 strokeState = Base::_strokeWidth > 1 ? ((dx > dy) ? 1 : 2) : 0;
|
|
// Stroke widths before and after the coordinate
|
|
// Before is favoured in case of even stroke width
|
|
int stb = Base::_strokeWidth >> 1;
|
|
int sta = stb + (Base::_strokeWidth & 1);
|
|
int xdir = (x2 > x1) ? 1 : -1;
|
|
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
*ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (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;
|
|
|
|
if (strokeState) {
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
*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;
|
|
if (strokeState) {
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (PixelType)color);
|
|
} else {
|
|
*ptr = (PixelType)color;
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
*ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (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 strokeState = Base::_strokeWidth > 1 ? ((dx > dy) ? 1 : 2) : 0;
|
|
// Stroke widths before and after the coordinate
|
|
// Before is favoured in case of even stroke width
|
|
int stb = Base::_strokeWidth >> 1;
|
|
int sta = stb + (Base::_strokeWidth & 1);
|
|
int xdir = (x2 > x1) ? 1 : -1;
|
|
int ptr_x = x1, ptr_y = y1;
|
|
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
if (IS_IN_CLIP(ptr_x, ptr_y + i)) *(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFillClip<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor, ptr_x - stb, ptr_y, _clippingArea);
|
|
}
|
|
|
|
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 (strokeState) {
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
if (IS_IN_CLIP(ptr_x, ptr_y + i)) *(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
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 (strokeState) {
|
|
colorFillClip<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor, ptr_x - stb, ptr_y, _clippingArea);
|
|
} else {
|
|
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
|
|
ptr_x = x2; ptr_y = y2;
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
if (IS_IN_CLIP(ptr_x, ptr_y + i)) *(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFillClip<PixelType>(ptr - stb, ptr + sta, (PixelType)_fgColor, ptr_x - stb, ptr_y, _clippingArea);
|
|
}
|
|
}
|
|
|
|
/** 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>::
|
|
drawTriangleHorzAlg(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_w = 0;
|
|
int x_pitch_sign = 1;
|
|
if (!inverted) {
|
|
x1 += w;
|
|
x_pitch_sign = -1;
|
|
}
|
|
|
|
PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
|
|
PixelType *floor = ptr_bottom - pitch;
|
|
PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + h);
|
|
|
|
int x2 = x1 + w;
|
|
int y2 = y1 + h / 2;
|
|
|
|
#if FIXED_POINT
|
|
int dx = (x2 - x1) << 8;
|
|
int dy = (y2 - y1) << 8;
|
|
|
|
if (abs(dy) > abs(dx)) {
|
|
#else
|
|
double dx = (double)x2 - (double)x1;
|
|
double dy = (double)y2 - (double)y1;
|
|
|
|
if (fabs(dy) > fabs(dx)) {
|
|
#endif
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
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 = (dx << 8) / dy;
|
|
int interx = (x1 << 8) + gradient;
|
|
#else
|
|
double gradient = dx / dy;
|
|
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_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
}
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
|
|
interx += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
*ptr_top = *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
|
|
blendPixelPtr(ptr_bottom, color, rfpart(interx));
|
|
blendPixelPtr(ptr_top, color, rfpart(interx));
|
|
break;
|
|
case kFillGradient:
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
|
|
blendPixelPtr(ptr_bottom, color, rfpart(interx));
|
|
blendPixelPtr(ptr_top, color, rfpart(interx));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
if (abs(dy) < abs(dx)) {
|
|
#else
|
|
if (fabs(dy) < fabs(dx)) {
|
|
#endif
|
|
ptr_top -= pitch;
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
blendPixelPtr(floor, color, 50);
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
int gradient = (dy << 8) / (dx + 0x100);
|
|
int intery = (y1 << 8) + gradient;
|
|
#else
|
|
double gradient = dy / (dx + 1);
|
|
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_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
}
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
|
|
intery += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
*ptr_top = *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
|
|
blendPixelPtr(ptr_bottom, color, rfpart(intery));
|
|
blendPixelPtr(ptr_top, color, rfpart(intery));
|
|
break;
|
|
case kFillGradient:
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
|
|
blendPixelPtr(ptr_bottom, color, rfpart(intery));
|
|
blendPixelPtr(ptr_top, color, rfpart(intery));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ptr_top -= pitch;
|
|
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
blendPixelPtr(floor, color, 50);
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
int gradient = (dy / dx) << 8;
|
|
int intery = (y1 << 8) + gradient;
|
|
#else
|
|
double gradient = dy / dx;
|
|
double intery = y1 + gradient;
|
|
#endif
|
|
|
|
for (int x = x1 + 1; x < x2; x++) {
|
|
ptr_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
|
|
intery += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
*ptr_top = *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFill<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color);
|
|
blendPixelPtr(ptr_bottom, color, rfpart(intery));
|
|
blendPixelPtr(ptr_top, color, rfpart(intery));
|
|
break;
|
|
case kFillGradient:
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w));
|
|
blendPixelPtr(ptr_bottom, color, rfpart(intery));
|
|
blendPixelPtr(ptr_top, color, rfpart(intery));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/////////////
|
|
|
|
template<typename PixelType>
|
|
void VectorRendererSpec<PixelType>::
|
|
drawTriangleHorzAlgClip(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_w = 0;
|
|
int x_pitch_sign = 1;
|
|
if (!inverted) {
|
|
x1 += w;
|
|
x_pitch_sign = -1;
|
|
}
|
|
|
|
PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
|
|
PixelType *floor = ptr_bottom - pitch;
|
|
PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + h);
|
|
|
|
int x2 = x1 + w;
|
|
int y2 = y1 + h / 2;
|
|
int x_bottom = x1;
|
|
int y_bottom = y1;
|
|
int x_top = x1;
|
|
int y_top = y1 + h;
|
|
int x_floor = x_bottom;
|
|
int y_floor = y_bottom - 1;
|
|
|
|
#if FIXED_POINT
|
|
int dx = (x2 - x1) << 8;
|
|
int dy = (y2 - y1) << 8;
|
|
|
|
if (abs(dy) > abs(dx)) {
|
|
#else
|
|
double dx = (double)x2 - (double)x1;
|
|
double dy = (double)y2 - (double)y1;
|
|
|
|
if (fabs(dy) > fabs(dx)) {
|
|
#endif
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
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 = (dx << 8) / dy;
|
|
int interx = (x1 << 8) + gradient;
|
|
#else
|
|
double gradient = dx / dy;
|
|
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_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
++y_bottom;
|
|
--y_top;
|
|
}
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
x_top += x_pitch_sign;
|
|
x_bottom += x_pitch_sign;
|
|
|
|
interx += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
|
|
if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(interx), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(interx), x_top, y_top);
|
|
break;
|
|
case kFillGradient:
|
|
colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(interx), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(interx), x_top, y_top);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
if (abs(dy) < abs(dx)) {
|
|
#else
|
|
if (fabs(dy) < fabs(dx)) {
|
|
#endif
|
|
ptr_top -= pitch;
|
|
--y_top;
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
blendPixelPtrClip(floor, color, 50, x_floor, ++y_floor);
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
int gradient = (dy << 8) / (dx + 0x100);
|
|
int intery = (y1 << 8) + gradient;
|
|
#else
|
|
double gradient = dy / (dx + 1);
|
|
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_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
++y_bottom;
|
|
--y_top;
|
|
}
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
x_bottom += x_pitch_sign;
|
|
x_top += x_pitch_sign;
|
|
|
|
intery += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
|
|
if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
|
|
break;
|
|
case kFillGradient:
|
|
colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ptr_top -= pitch;
|
|
--y_top;
|
|
while (floor != ptr_top) {
|
|
floor += pitch;
|
|
blendPixelPtrClip(floor, color, 50, x_floor, ++y_floor);
|
|
}
|
|
|
|
#if FIXED_POINT
|
|
int gradient = (dy / dx) << 8;
|
|
int intery = (y1 << 8) + gradient;
|
|
#else
|
|
double gradient = dy / dx;
|
|
double intery = y1 + gradient;
|
|
#endif
|
|
|
|
for (int x = x1 + 1; x < x2; x++) {
|
|
ptr_bottom += pitch;
|
|
ptr_top -= pitch;
|
|
++y_bottom;
|
|
--y_top;
|
|
|
|
ptr_top += x_pitch_sign;
|
|
ptr_bottom += x_pitch_sign;
|
|
x_bottom += x_pitch_sign;
|
|
x_top += x_pitch_sign;
|
|
|
|
intery += gradient;
|
|
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
if (IS_IN_CLIP(x_top, y_top)) *ptr_top = color;
|
|
if (IS_IN_CLIP(x_bottom, y_bottom)) *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFillClip<PixelType>(ptr_bottom + pitch, ptr_top, pitch, color, x_bottom, y_bottom + 1, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
|
|
break;
|
|
case kFillGradient:
|
|
colorVFillClip<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, w), x_bottom, y_bottom, _clippingArea);
|
|
blendPixelPtrClip(ptr_bottom, color, rfpart(intery), x_bottom, y_bottom);
|
|
blendPixelPtrClip(ptr_top, color, rfpart(intery), x_top, y_top);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////
|
|
|
|
/** HORIZONTAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
|
|
template<typename PixelType>
|
|
void VectorRendererSpec<PixelType>::
|
|
drawTriangleFastH(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;
|
|
int x_pitch_sign = 1;
|
|
|
|
if (!inverted) {
|
|
y1 += size;
|
|
x_pitch_sign = -1;
|
|
}
|
|
|
|
int gradient_w = 0;
|
|
PixelType *ptr_bottom = (PixelType *)_activeSurface->getBasePtr(x1, y1);
|
|
PixelType *ptr_top = (PixelType *)_activeSurface->getBasePtr(x1, y1 + size);
|
|
int x2 = x1 + size;
|
|
int y2 = y1 + size / 2;
|
|
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;
|
|
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, color);
|
|
|
|
while (1) {
|
|
switch (fill_m) {
|
|
case kFillDisabled:
|
|
*ptr_top = *ptr_bottom = color;
|
|
break;
|
|
case kFillForeground:
|
|
case kFillBackground:
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, color);
|
|
break;
|
|
case kFillGradient:
|
|
colorVFill<PixelType>(ptr_bottom, ptr_top, pitch, calcGradient(gradient_w++, size));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (x1 == x2 && y1 == y2)
|
|
break;
|
|
|
|
int error2 = error * 2;
|
|
|
|
if (error2 > -deltaX) {
|
|
error -= deltaX;
|
|
y1 += signY;
|
|
ptr_bottom += signY * pitch;
|
|
ptr_top += -signY * pitch;
|
|
}
|
|
|
|
if (error2 < deltaY) {
|
|
error += deltaY;
|
|
x1 += signX;
|
|
ptr_bottom += x_pitch_sign;
|
|
ptr_top += x_pitch_sign;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
default:
|
|
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;
|
|
default:
|
|
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;
|
|
default:
|
|
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;
|
|
default:
|
|
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;
|
|
default:
|
|
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;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////
|
|
|
|
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
|
|
template<typename PixelType>
|
|
void VectorRendererSpec<PixelType>::
|
|
drawTriangleFastV(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;
|
|
default:
|
|
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;
|
|
|
|
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) {
|
|
PixelType *ptr_fill3 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + sw - 1);
|
|
this->blendFill(ptr_fill3 + r, ptr_fill3 + w + 1 - r, color1, alpha_t); // top
|
|
|
|
PixelType *ptr_fill2 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h - sw + 1);
|
|
this->blendFill(ptr_fill2 + r, ptr_fill2 + w + 1 - r, color2, alpha_b); // bottom
|
|
|
|
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(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, color, alpha_l); // left
|
|
blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, 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, uint32 shadowIntensity) {
|
|
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;
|
|
|
|
// The shadow is cast down and to the right, by 'offset' pixels on both sides
|
|
Common::Rect shadowRect(w + offset, h + offset);
|
|
shadowRect.translate(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.
|
|
|
|
// HACK: shadowIntensity is tailed with 16-bits mantissa. We also represent the
|
|
// offset as a 16.16 fixed point number here as termination condition to simplify
|
|
// looping logic. An additional `shadowIntensity` is added to to keep consistent
|
|
// with previous implementation.
|
|
uint32 targetOffset = (uint32)(offset << 16) + shadowIntensity;
|
|
int curOffset = 0;
|
|
for (uint32 i = shadowIntensity; i <= targetOffset; i += shadowIntensity) {
|
|
int f, ddF_x, ddF_y;
|
|
int x, y, px, py;
|
|
|
|
// No more room to draw: abort
|
|
if ((shadowRect.width() < 2*r) ||
|
|
(shadowRect.height() < 2*r)) {
|
|
break;
|
|
}
|
|
|
|
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(curOffset - (i >> 16));
|
|
curOffset = i >> 16;
|
|
|
|
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, uint32 shadowIntensity) {
|
|
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;
|
|
|
|
// The shadow is cast down and to the right, by 'offset' pixels on both sides
|
|
Common::Rect shadowRect(w + offset, h + offset);
|
|
shadowRect.translate(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.
|
|
|
|
// HACK: shadowIntensity is tailed with 16-bits mantissa. We also represent the
|
|
// offset as a 16.16 fixed point number here as termination condition to simplify
|
|
// looping logic. An additional `shadowIntensity` is added to to keep consistent
|
|
// with previous implementation.
|
|
uint32 targetOffset = (uint32)(offset << 16) + shadowIntensity;
|
|
int curOffset = 0;
|
|
for (uint32 i = shadowIntensity; i <= targetOffset; i += shadowIntensity) {
|
|
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(curOffset - (i >> 16));
|
|
curOffset = i >> 16;
|
|
|
|
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 strokeState = Base::_strokeWidth > 1 ? ((dx > dy) ? 1 : 2) : 0;
|
|
// Stroke widths before and after the coordinate
|
|
// Before is favoured in case of even stroke width
|
|
int stb = Base::_strokeWidth >> 1;
|
|
int sta = stb + (Base::_strokeWidth & 1);
|
|
int xdir = (x2 > x1) ? 1 : -1;
|
|
uint16 error_tmp, error_acc, gradient;
|
|
uint8 alpha;
|
|
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
*ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (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);
|
|
|
|
if (strokeState) {
|
|
intptr p = -stb * pitch;
|
|
this->blendPixelPtr(ptr + p, color, ~alpha);
|
|
p += pitch;
|
|
for (int i = -stb + 1; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
this->blendPixelPtr(ptr + p, color, alpha);
|
|
} else {
|
|
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);
|
|
|
|
if (strokeState) {
|
|
if (xdir > 0) {
|
|
this->blendPixelPtr(ptr - stb, color, ~alpha);
|
|
colorFill<PixelType>(ptr - stb + 1, ptr + sta, (PixelType)color);
|
|
this->blendPixelPtr(ptr + sta, color, alpha);
|
|
} else {
|
|
this->blendPixelPtr(ptr - stb, color, alpha);
|
|
colorFill<PixelType>(ptr - stb + 1, ptr + sta, (PixelType)color);
|
|
this->blendPixelPtr(ptr + sta, color, ~alpha);
|
|
}
|
|
} else {
|
|
this->blendPixelPtr(ptr, color, ~alpha);
|
|
this->blendPixelPtr(ptr + xdir, color, alpha);
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = (PixelType *)Base::_activeSurface->getBasePtr(x2, y2);
|
|
if (strokeState == 0) {
|
|
// No stroke width
|
|
*ptr = (PixelType)color;
|
|
} else if (strokeState == 1) {
|
|
// Horizontal line
|
|
intptr p = -stb * pitch;
|
|
for (int i = -stb; i < sta; i++, p += pitch) {
|
|
*(ptr + p) = (PixelType)color;
|
|
}
|
|
} else {
|
|
// Vertical line
|
|
colorFill<PixelType>(ptr - stb, ptr + sta, (PixelType)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, bool vFlip) {
|
|
// 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;
|
|
|
|
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, color3, color4;
|
|
color1 = color2 = color3 = color4 = color;
|
|
|
|
int long_h = h;
|
|
int short_h = h - real_radius;
|
|
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;
|
|
int short_h = h - 2 * r;
|
|
|
|
int strokeWidth = Base::_strokeWidth;
|
|
|
|
while (sw++ < strokeWidth) {
|
|
PixelType *ptr_fill3 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + sw - 1);
|
|
this->blendFill(ptr_fill3 + r, ptr_fill3 + w + 1 - r, color, alpha_t); // top
|
|
|
|
PixelType *ptr_fill2 = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h - sw + 1);
|
|
this->blendFill(ptr_fill2 + r, ptr_fill2 + w + 1 - r, color, alpha_b); // bottom
|
|
|
|
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 > 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
|
|
|
|
}
|