From b089d9bf204b1eb783a10f310badc5d2cf836772 Mon Sep 17 00:00:00 2001 From: Michael Liebmann Date: Thu, 16 May 2013 08:27:24 +0200 Subject: [PATCH] * CFrameBuffer: Rework paintBoxFrame() - Rounded corners can be displayed individually - Improved rendering of circular arcs - Remove duplicate code in paintBoxRel() --- src/driver/framebuffer.cpp | 289 +++++++++++++++++++++---------------- src/driver/framebuffer.h | 22 ++- 2 files changed, 184 insertions(+), 127 deletions(-) diff --git a/src/driver/framebuffer.cpp b/src/driver/framebuffer.cpp index fdac73996..b49788b58 100644 --- a/src/driver/framebuffer.cpp +++ b/src/driver/framebuffer.cpp @@ -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) diff --git a/src/driver/framebuffer.h b/src/driver/framebuffer.h index 27218ac7f..6b37f3ffe 100644 --- a/src/driver/framebuffer.h +++ b/src/driver/framebuffer.h @@ -111,30 +111,40 @@ class CFrameBuffer bool active; static void switch_signal (int); fb_fix_screeninfo fix; - #ifdef USE_NEVIS_GXA +#ifdef USE_NEVIS_GXA 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 */ volatile uint8_t *gxa_base; /* base address for the GXA's register access */ - - #endif /* USE_NEVIS_GXA */ +#endif /* USE_NEVIS_GXA */ bool locked; std::map icon_cache; 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); int m_transparent_default, m_transparent; // Unlocked versions (no mutex) 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 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: fb_pixel_t realcolor[256]; ~CFrameBuffer(); static CFrameBuffer* getInstance(); - #ifdef USE_NEVIS_GXA +#ifdef USE_NEVIS_GXA void setupGXA(void); - #endif +#endif void init(const char * const fbDevice = "/dev/fb/0"); int setMode(unsigned int xRes, unsigned int yRes, unsigned int bpp); @@ -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, 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); inline void paintVLine(int x, int ya, int yb, const fb_pixel_t col) { paintVLineRel(x, ya, yb - ya, col); }