* CFrameBuffer: Rework paintBoxFrame()

- Rounded corners can be displayed individually
- Improved rendering of circular arcs
- Remove duplicate code in paintBoxRel()
This commit is contained in:
Michael Liebmann
2013-05-16 08:27:24 +02:00
parent bf1c7bfdb7
commit b089d9bf20
2 changed files with 184 additions and 127 deletions

View File

@@ -198,6 +198,12 @@ CFrameBuffer::CFrameBuffer()
// TM_NONE: No 'pseudo' transparency
// TM_INI: Transparency depends on g_settings.infobar_alpha ???
m_transparent = m_transparent_default;
q_circle = NULL;
initQCircle();
corner_tl = false;
corner_tr = false;
corner_bl = false;
corner_br = false;
//FIXME: test
memset(red, 0, 256*sizeof(__u16));
memset(green, 0, 256*sizeof(__u16));
@@ -391,6 +397,11 @@ CFrameBuffer::~CFrameBuffer()
backupBackground = NULL;
}
if (q_circle) {
delete[] q_circle;
q_circle = NULL;
}
#if 0
#ifdef RETURN_FROM_GRAPHICS_MODE
if (-1 == ioctl(tty,KDSETMODE, kd_mode))
@@ -678,83 +689,14 @@ void CFrameBuffer::paintBoxRel(const int x, const int y, const int dx, const int
_write_gxa(gxa_base, GXA_BG_COLOR_REG, (unsigned int) col); /* setup the drawing color */
#endif
/* this table contains the x coordinates for a quarter circle (the bottom right quarter) with fixed
radius of 540 px which is the half of the max HD graphics size of 1080 px. So with that table we
ca draw boxes with round corners and als circles by just setting dx = dy = radius (max 540). */
static const int q_circle[541] = {
540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540,
540, 540, 540, 540, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539,
539, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 537, 537, 537, 537, 537, 537, 537,
537, 537, 536, 536, 536, 536, 536, 536, 536, 536, 535, 535, 535, 535, 535, 535, 535, 535, 534, 534,
534, 534, 534, 534, 533, 533, 533, 533, 533, 533, 532, 532, 532, 532, 532, 532, 531, 531, 531, 531,
531, 531, 530, 530, 530, 530, 529, 529, 529, 529, 529, 529, 528, 528, 528, 528, 527, 527, 527, 527,
527, 526, 526, 526, 526, 525, 525, 525, 525, 524, 524, 524, 524, 523, 523, 523, 523, 522, 522, 522,
522, 521, 521, 521, 521, 520, 520, 520, 519, 519, 519, 518, 518, 518, 518, 517, 517, 517, 516, 516,
516, 515, 515, 515, 515, 514, 514, 514, 513, 513, 513, 512, 512, 512, 511, 511, 511, 510, 510, 510,
509, 509, 508, 508, 508, 507, 507, 507, 506, 506, 506, 505, 505, 504, 504, 504, 503, 503, 502, 502,
502, 501, 501, 500, 500, 499, 499, 499, 498, 498, 498, 497, 497, 496, 496, 496, 495, 495, 494, 494,
493, 493, 492, 492, 491, 491, 490, 490, 490, 489, 489, 488, 488, 487, 487, 486, 486, 485, 485, 484,
484, 483, 483, 482, 482, 481, 481, 480, 480, 479, 479, 478, 478, 477, 477, 476, 476, 475, 475, 474,
473, 473, 472, 472, 471, 471, 470, 470, 469, 468, 468, 467, 466, 466, 465, 465, 464, 464, 463, 462,
462, 461, 460, 460, 459, 459, 458, 458, 457, 456, 455, 455, 454, 454, 453, 452, 452, 451, 450, 450,
449, 449, 448, 447, 446, 446, 445, 445, 444, 443, 442, 441, 441, 440, 440, 439, 438, 437, 436, 436,
435, 435, 434, 433, 432, 431, 431, 430, 429, 428, 427, 427, 426, 425, 425, 424, 423, 422, 421, 421,
420, 419, 418, 417, 416, 416, 415, 414, 413, 412, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403,
403, 402, 401, 400, 399, 398, 397, 397, 395, 394, 393, 393, 392, 391, 390, 389, 388, 387, 386, 385,
384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 369, 368, 367, 367, 365, 364,
363, 362, 361, 360, 358, 357, 356, 355, 354, 353, 352, 351, 350, 348, 347, 346, 345, 343, 342, 341,
340, 339, 337, 336, 335, 334, 332, 331, 329, 328, 327, 326, 324, 323, 322, 321, 319, 317, 316, 315,
314, 312, 310, 309, 308, 307, 305, 303, 302, 301, 299, 297, 296, 294, 293, 291, 289, 288, 287, 285,
283, 281, 280, 278, 277, 275, 273, 271, 270, 268, 267, 265, 263, 261, 259, 258, 256, 254, 252, 250,
248, 246, 244, 242, 240, 238, 236, 234, 232, 230, 228, 225, 223, 221, 219, 217, 215, 212, 210, 207,
204, 202, 200, 197, 195, 192, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 160, 157, 154, 150,
147, 144, 140, 136, 132, 128, 124, 120, 115, 111, 105, 101, 95, 89, 83, 77, 69, 61, 52, 40,
23};
int line = 0;
if (type && radius) {
bool corner_tl = (type & CORNER_TOP_LEFT) == CORNER_TOP_LEFT;
bool corner_tr = (type & CORNER_TOP_RIGHT) == CORNER_TOP_RIGHT;
bool corner_bl = (type & CORNER_BOTTOM_LEFT) == CORNER_BOTTOM_LEFT;
bool corner_br = (type & CORNER_BOTTOM_RIGHT)== CORNER_BOTTOM_RIGHT;
int ofs, scf, scl, ofl, ofr;
/* just an multiplicator for all math to reduce rounding errors */
#define MUL 32768
/* limit the radius */
if (radius > dx)
radius = dx;
if (radius > dy)
radius = dy;
if (radius > 540)
radius = 540;
scf = (540 * MUL) / ((radius < 1) ? 1 : radius);
setCornerFlags(type);
radius = limitRadius(dx, dy, radius);
while (line < dy) {
ofl = ofr = 0;
if (line < radius && (type & CORNER_TOP)) {/* one of the top corners */
//printf("1: x %d y %d dx %d dy %d rad %d line %d\n", x, y, dx, dy, radius, line);
/* uper round corners */
scl = scf * (radius - line) / MUL;
if ((scf * (radius - line) % MUL) >= (MUL / 2)) /* round up */
scl++;
ofs = radius - (q_circle[scl] * MUL / scf);
// ofl = corner_tl * ofs; // might depend on the arch if multiply is faster or not
ofl = corner_tl ? ofs : 0;
ofr = corner_tr ? ofs : 0;
} else if ((line >= dy - radius) && (type & CORNER_BOTTOM)) { /* one of the bottom corners */
//printf("2: x %d y %d dx %d dy %d rad %d line %d\n", x, y, dx, dy, radius, line);
/* lower round corners */
scl = scf * (radius - (dy - (line + 1))) / MUL;
if ((scf * (radius - (dy - (line + 1))) % MUL) >= (MUL / 2)) /* round up */
scl++;
ofs = radius - (q_circle[scl] * MUL / scf);
ofl = corner_bl ? ofs : 0;
ofr = corner_br ? ofs : 0;
} else {
int ofl, ofr;
if (calcCorners(NULL, &ofl, &ofr, dy, line, radius, type)) {
//printf("3: x %d y %d dx %d dy %d rad %d line %d\n", x, y, dx, dy, radius, line);
#if defined(FB_HW_ACCELERATION) || defined(USE_NEVIS_GXA)
int rect_height_mult = ((type & CORNER_TOP) && (type & CORNER_BOTTOM)) ? 2 : 1;
@@ -1143,65 +1085,170 @@ void CFrameBuffer::paintPixel(const int x, const int y, const fb_pixel_t col)
#endif
}
void CFrameBuffer::paintBoxFrame(const int sx, const int sy, const int dx, const int dy, const int px, const fb_pixel_t col, const int rad)
void CFrameBuffer::paintShortHLineRelInternal(const int& x, const int& dx, const int& y, const fb_pixel_t& col)
{
uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y;
fb_pixel_t * dest = (fb_pixel_t *)pos;
for (int i = 0; i < dx; i++)
*(dest++) = col;
}
int CFrameBuffer::limitRadius(const int& dx, const int& dy, int& radius)
{
if (radius > dx)
return dx;
if (radius > dy)
return dy;
if (radius > 540)
return 540;
return radius;
}
void CFrameBuffer::setCornerFlags(const int& type)
{
corner_tl = (type & CORNER_TOP_LEFT) == CORNER_TOP_LEFT;
corner_tr = (type & CORNER_TOP_RIGHT) == CORNER_TOP_RIGHT;
corner_bl = (type & CORNER_BOTTOM_LEFT) == CORNER_BOTTOM_LEFT;
corner_br = (type & CORNER_BOTTOM_RIGHT) == CORNER_BOTTOM_RIGHT;
}
void CFrameBuffer::initQCircle()
{
/* this table contains the x coordinates for a quarter circle (the bottom right quarter) with fixed
radius of 540 px which is the half of the max HD graphics size of 1080 px. So with that table we
ca draw boxes with round corners and als circles by just setting dx = dy = radius (max 540). */
static const int _q_circle[541] = {
540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540,
540, 540, 540, 540, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539,
539, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 537, 537, 537, 537, 537, 537, 537,
537, 537, 536, 536, 536, 536, 536, 536, 536, 536, 535, 535, 535, 535, 535, 535, 535, 535, 534, 534,
534, 534, 534, 534, 533, 533, 533, 533, 533, 533, 532, 532, 532, 532, 532, 532, 531, 531, 531, 531,
531, 531, 530, 530, 530, 530, 529, 529, 529, 529, 529, 529, 528, 528, 528, 528, 527, 527, 527, 527,
527, 526, 526, 526, 526, 525, 525, 525, 525, 524, 524, 524, 524, 523, 523, 523, 523, 522, 522, 522,
522, 521, 521, 521, 521, 520, 520, 520, 519, 519, 519, 518, 518, 518, 518, 517, 517, 517, 516, 516,
516, 515, 515, 515, 515, 514, 514, 514, 513, 513, 513, 512, 512, 512, 511, 511, 511, 510, 510, 510,
509, 509, 508, 508, 508, 507, 507, 507, 506, 506, 506, 505, 505, 504, 504, 504, 503, 503, 502, 502,
502, 501, 501, 500, 500, 499, 499, 499, 498, 498, 498, 497, 497, 496, 496, 496, 495, 495, 494, 494,
493, 493, 492, 492, 491, 491, 490, 490, 490, 489, 489, 488, 488, 487, 487, 486, 486, 485, 485, 484,
484, 483, 483, 482, 482, 481, 481, 480, 480, 479, 479, 478, 478, 477, 477, 476, 476, 475, 475, 474,
473, 473, 472, 472, 471, 471, 470, 470, 469, 468, 468, 467, 466, 466, 465, 465, 464, 464, 463, 462,
462, 461, 460, 460, 459, 459, 458, 458, 457, 456, 455, 455, 454, 454, 453, 452, 452, 451, 450, 450,
449, 449, 448, 447, 446, 446, 445, 445, 444, 443, 442, 441, 441, 440, 440, 439, 438, 437, 436, 436,
435, 435, 434, 433, 432, 431, 431, 430, 429, 428, 427, 427, 426, 425, 425, 424, 423, 422, 421, 421,
420, 419, 418, 417, 416, 416, 415, 414, 413, 412, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403,
403, 402, 401, 400, 399, 398, 397, 397, 395, 394, 393, 393, 392, 391, 390, 389, 388, 387, 386, 385,
384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 369, 368, 367, 367, 365, 364,
363, 362, 361, 360, 358, 357, 356, 355, 354, 353, 352, 351, 350, 348, 347, 346, 345, 343, 342, 341,
340, 339, 337, 336, 335, 334, 332, 331, 329, 328, 327, 326, 324, 323, 322, 321, 319, 317, 316, 315,
314, 312, 310, 309, 308, 307, 305, 303, 302, 301, 299, 297, 296, 294, 293, 291, 289, 288, 287, 285,
283, 281, 280, 278, 277, 275, 273, 271, 270, 268, 267, 265, 263, 261, 259, 258, 256, 254, 252, 250,
248, 246, 244, 242, 240, 238, 236, 234, 232, 230, 228, 225, 223, 221, 219, 217, 215, 212, 210, 207,
204, 202, 200, 197, 195, 192, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 160, 157, 154, 150,
147, 144, 140, 136, 132, 128, 124, 120, 115, 111, 105, 101, 95, 89, 83, 77, 69, 61, 52, 40,
23};
if (q_circle == NULL)
q_circle = new int[sizeof(_q_circle) / sizeof(int)];
memcpy(q_circle, _q_circle, sizeof(_q_circle));
}
bool CFrameBuffer::calcCorners(int *ofs, int *ofl, int *ofr, const int& dy, const int& line, const int& radius, const int& type)
{
/* just an multiplicator for all math to reduce rounding errors */
#define MUL 32768
int scl, _ofs = 0;
bool ret = false;
if (ofl != NULL) *ofl = 0;
if (ofr != NULL) *ofr = 0;
int scf = (540 * MUL) / ((radius < 1) ? 1 : radius);
/* one of the top corners */
if (line < radius && (type & CORNER_TOP)) {
/* uper round corners */
scl = scf * (radius - line) / MUL;
if ((scf * (radius - line) % MUL) >= (MUL / 2)) /* round up */
scl++;
_ofs = radius - (q_circle[scl] * MUL / scf);
if (ofl != NULL) *ofl = corner_tl ? _ofs : 0;
if (ofr != NULL) *ofr = corner_tr ? _ofs : 0;
}
/* one of the bottom corners */
else if ((line >= dy - radius) && (type & CORNER_BOTTOM)) {
/* lower round corners */
scl = scf * (radius - (dy - (line + 1))) / MUL;
if ((scf * (radius - (dy - (line + 1))) % MUL) >= (MUL / 2)) /* round up */
scl++;
_ofs = radius - (q_circle[scl] * MUL / scf);
if (ofl != NULL) *ofl = corner_bl ? _ofs : 0;
if (ofr != NULL) *ofr = corner_br ? _ofs : 0;
}
else
ret = true;
if (ofs != NULL) *ofs = _ofs;
return ret;
}
void CFrameBuffer::paintBoxFrame(const int x, const int y, const int dx, const int dy, const int px, const fb_pixel_t col, int radius, int type)
{
if (!getActive())
return;
int radius = rad;
int c_radius = rad << 1;
paintBoxRel(sx + rad , sy , dx - c_radius, px, col); // upper horizontal
paintBoxRel(sx + rad , sy + dy - px, dx - c_radius, px, col); // lower horizontal
paintBoxRel(sx , sy + rad , px, dy - c_radius , col); // left vertical
paintBoxRel(sx + dx - px, sy + rad , px, dy - c_radius , col); // right vertical
if (!radius)
{
if (dx == 0 || dy == 0) {
printf("paintBoxFrame: radius %d, start x %d y %d end x %d y %d\n", radius, x, y, x+dx, y+dy);
return;
}
int x1 = sx + radius;
int y1 = sy + radius;
int x2 = sx + dx - radius -1;
int y2 = sy + dy - radius -1;
setCornerFlags(type);
int rad_tl = 0, rad_tr = 0, rad_bl = 0, rad_br = 0;
if (type && radius) {
int x_rad = radius - 1;
if (corner_tl) rad_tl = x_rad;
if (corner_tr) rad_tr = x_rad;
if (corner_bl) rad_bl = x_rad;
if (corner_br) rad_br = x_rad;
}
paintBoxRel(x + rad_tl , y , dx - rad_tl - rad_tr, px , col); // top horizontal
paintBoxRel(x + rad_bl , y + dy - px, dx - rad_bl - rad_br, px , col); // bottom horizontal
paintBoxRel(x , y + rad_tl , px , dy - rad_tl - rad_bl, col); // left vertical
paintBoxRel(x + dx - px, y + rad_tr , px , dy - rad_tr - rad_br, col); // right vertical
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = - c_radius;
int x = 0;
int y = radius;
if (type && radius) {
radius = limitRadius(dx, dy, radius);
int line = 0;
waitForIdle();
while (line < dy) {
int ofs = 0, ofs_i = 0;
// inner box
if ((line >= px) && (line < (dy - px)))
ofs_i = calcCornersOffset(dy - 2*px, line-px, radius-px, type);
// outer box
ofs = calcCornersOffset(dy, line, radius, type);
while(x < y)
{
// ddF_x == 2 * x + 1;
// ddF_y == -2 * y;
// f == x*x + y*y - radius*radius + 2*x - y + 1;
if(f >= 0)
{
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
int width = 0;
while (width <= px)
{
paintPixel(x2 + x , y1 - y + width, col); // 1. oct
paintPixel(x2 + y - width, y1 - x , col); // 2. oct
paintPixel(x2 + y - width, y2 + x , col); // 3. oct
paintPixel(x2 + x , y2 + y - width, col); // 4. oct
paintPixel(x1 - x , y2 + y - width, col); // 5. oct
paintPixel(x1 - y + width, y2 + x , col); // 6. oct
paintPixel(x1 - y + width, y1 - x , col); // 7. oct
paintPixel(x1 - x , y1 - y + width, col); // 8. oct
width++;
int _x = x + ofs;
int _x_end = x + dx;
int _y = y + line;
if ((line < px) || (line >= (dy - px))) {
// left
if (((corner_tl) && (line < radius)) || ((corner_bl) && (line >= dy - radius)))
paintShortHLineRelInternal(_x, radius - ofs, _y, col);
// right
if (((corner_tr) && (line < radius)) || ((corner_br) && (line >= dy - radius)))
paintShortHLineRelInternal(_x_end - radius, radius - ofs, _y, col);
}
else if (line < (dy - px)) {
int _dx = (ofs_i-ofs) + px;
// left
if (((corner_tl) && (line < radius)) || ((corner_bl) && (line >= dy - radius)))
paintShortHLineRelInternal(_x, _dx, _y, col);
// right
if (((corner_tr) && (line < radius)) || ((corner_br) && (line >= dy - radius)))
paintShortHLineRelInternal(_x_end - ofs_i - px, _dx, _y, col);
}
if ((line == radius) && (dy > 2*radius))
// line outside the rounded corners
line = dy - radius;
else
line++;
}
}
}
void CFrameBuffer::paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col)