* 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_NONE: No 'pseudo' transparency
// TM_INI: Transparency depends on g_settings.infobar_alpha ??? // TM_INI: Transparency depends on g_settings.infobar_alpha ???
m_transparent = m_transparent_default; m_transparent = m_transparent_default;
q_circle = NULL;
initQCircle();
corner_tl = false;
corner_tr = false;
corner_bl = false;
corner_br = false;
//FIXME: test //FIXME: test
memset(red, 0, 256*sizeof(__u16)); memset(red, 0, 256*sizeof(__u16));
memset(green, 0, 256*sizeof(__u16)); memset(green, 0, 256*sizeof(__u16));
@@ -391,6 +397,11 @@ CFrameBuffer::~CFrameBuffer()
backupBackground = NULL; backupBackground = NULL;
} }
if (q_circle) {
delete[] q_circle;
q_circle = NULL;
}
#if 0 #if 0
#ifdef RETURN_FROM_GRAPHICS_MODE #ifdef RETURN_FROM_GRAPHICS_MODE
if (-1 == ioctl(tty,KDSETMODE, kd_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 */ _write_gxa(gxa_base, GXA_BG_COLOR_REG, (unsigned int) col); /* setup the drawing color */
#endif #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; int line = 0;
if (type && radius) { if (type && radius) {
bool corner_tl = (type & CORNER_TOP_LEFT) == CORNER_TOP_LEFT; setCornerFlags(type);
bool corner_tr = (type & CORNER_TOP_RIGHT) == CORNER_TOP_RIGHT; radius = limitRadius(dx, dy, radius);
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);
while (line < dy) { while (line < dy) {
ofl = ofr = 0; int ofl, ofr;
if (calcCorners(NULL, &ofl, &ofr, dy, line, radius, type)) {
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 {
//printf("3: x %d y %d dx %d dy %d rad %d line %d\n", x, y, dx, dy, radius, line); //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) #if defined(FB_HW_ACCELERATION) || defined(USE_NEVIS_GXA)
int rect_height_mult = ((type & CORNER_TOP) && (type & CORNER_BOTTOM)) ? 2 : 1; 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 #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()) if (!getActive())
return; return;
int radius = rad; if (dx == 0 || dy == 0) {
int c_radius = rad << 1; printf("paintBoxFrame: radius %d, start x %d y %d end x %d y %d\n", radius, x, y, x+dx, y+dy);
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)
{
return; return;
} }
int x1 = sx + radius; setCornerFlags(type);
int y1 = sy + radius; int rad_tl = 0, rad_tr = 0, rad_bl = 0, rad_br = 0;
int x2 = sx + dx - radius -1; if (type && radius) {
int y2 = sy + dy - radius -1; int x_rad = radius - 1;
if (corner_tl) rad_tl = x_rad;
int f = 1 - radius; if (corner_tr) rad_tr = x_rad;
int ddF_x = 1; if (corner_bl) rad_bl = x_rad;
int ddF_y = - c_radius; if (corner_br) rad_br = x_rad;
int x = 0;
int y = radius;
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++; paintBoxRel(x + rad_tl , y , dx - rad_tl - rad_tr, px , col); // top horizontal
ddF_x += 2; paintBoxRel(x + rad_bl , y + dy - px, dx - rad_bl - rad_br, px , col); // bottom horizontal
f += ddF_x; 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 width = 0; if (type && radius) {
while (width <= px) radius = limitRadius(dx, dy, radius);
{ int line = 0;
paintPixel(x2 + x , y1 - y + width, col); // 1. oct waitForIdle();
paintPixel(x2 + y - width, y1 - x , col); // 2. oct while (line < dy) {
paintPixel(x2 + y - width, y2 + x , col); // 3. oct int ofs = 0, ofs_i = 0;
paintPixel(x2 + x , y2 + y - width, col); // 4. oct // inner box
paintPixel(x1 - x , y2 + y - width, col); // 5. oct if ((line >= px) && (line < (dy - px)))
paintPixel(x1 - y + width, y2 + x , col); // 6. oct ofs_i = calcCornersOffset(dy - 2*px, line-px, radius-px, type);
paintPixel(x1 - y + width, y1 - x , col); // 7. oct // outer box
paintPixel(x1 - x , y1 - y + width, col); // 8. oct ofs = calcCornersOffset(dy, line, radius, type);
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) void CFrameBuffer::paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col)

View File

@@ -115,17 +115,27 @@ class CFrameBuffer
int devmem_fd; /* to access the GXA register we use /dev/mem */ int devmem_fd; /* to access the GXA register we use /dev/mem */
unsigned int smem_start; /* as aquired from the fbdev, the framebuffers physical start address */ unsigned int smem_start; /* as aquired from the fbdev, the framebuffers physical start address */
volatile uint8_t *gxa_base; /* base address for the GXA's register access */ volatile uint8_t *gxa_base; /* base address for the GXA's register access */
#endif /* USE_NEVIS_GXA */ #endif /* USE_NEVIS_GXA */
bool locked; bool locked;
std::map<std::string, rawIcon> icon_cache; std::map<std::string, rawIcon> icon_cache;
int cache_size; int cache_size;
int *q_circle;
bool corner_tl, corner_tr, corner_bl, corner_br;
void * int_convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int transp, bool alpha); void * int_convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int transp, bool alpha);
int m_transparent_default, m_transparent; int m_transparent_default, m_transparent;
// Unlocked versions (no mutex) // Unlocked versions (no mutex)
void paintHLineRelInternal(int x, int dx, int y, const fb_pixel_t col); void paintHLineRelInternal(int x, int dx, int y, const fb_pixel_t col);
void paintVLineRelInternal(int x, int y, int dy, const fb_pixel_t col); void paintVLineRelInternal(int x, int y, int dy, const fb_pixel_t col);
void paintShortHLineRelInternal(const int& x, const int& dx, const int& y, const fb_pixel_t& col);
int limitRadius(const int& dx, const int& dy, int& radius);
void setCornerFlags(const int& type);
void initQCircle();
inline int calcCornersOffset(const int& dy, const int& line, const int& radius, const int& type) { int ofs = 0; calcCorners(&ofs, NULL, NULL, dy, line, radius, type); return ofs; }
bool calcCorners(int *ofs, int *ofl, int *ofr, const int& dy, const int& line, const int& radius, const int& type);
public: public:
fb_pixel_t realcolor[256]; fb_pixel_t realcolor[256];
@@ -177,7 +187,7 @@ class CFrameBuffer
inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col) { paintBoxRel(xa, ya, xb - xa, yb - ya, col); } inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col) { paintBoxRel(xa, ya, xb - xa, yb - ya, col); }
inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col, int radius, int type) { paintBoxRel(xa, ya, xb - xa, yb - ya, col, radius, type); } inline void paintBox(int xa, int ya, int xb, int yb, const fb_pixel_t col, int radius, int type) { paintBoxRel(xa, ya, xb - xa, yb - ya, col, radius, type); }
void paintBoxFrame(const int x, const int y, const int dx, const int dy, const int px, const fb_pixel_t col, const int rad = 0); void paintBoxFrame(const int x, const int y, const int dx, const int dy, const int px, const fb_pixel_t col, int radius = 0, int type = CORNER_ALL);
void paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col); void paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col);
inline void paintVLine(int x, int ya, int yb, const fb_pixel_t col) { paintVLineRel(x, ya, yb - ya, col); } inline void paintVLine(int x, int ya, int yb, const fb_pixel_t col) { paintVLineRel(x, ya, yb - ya, col); }